From b31c6deb5f7ca80d838e7a9f1eda79bf59429119 Mon Sep 17 00:00:00 2001 From: laizy Date: Tue, 19 Sep 2017 15:46:09 +0800 Subject: [PATCH 1/4] add currBlockHeight in Transaction struct Signed-off-by: laizy --- consensus/dbft/dbftService.go | 21 +++++----- core/ledger/block.go | 4 +- core/transaction/transaction.go | 68 ++++++++++++++++++++++++++------- core/validation/txValidator.go | 16 ++++++++ errors/errcode.go | 7 +++- net/httpjsonrpc/common.go | 18 +++++---- net/httpjsonrpc/interfaces.go | 4 +- 7 files changed, 103 insertions(+), 35 deletions(-) diff --git a/consensus/dbft/dbftService.go b/consensus/dbft/dbftService.go index f17a534e..0aa5c0f5 100644 --- a/consensus/dbft/dbftService.go +++ b/consensus/dbft/dbftService.go @@ -174,16 +174,19 @@ func (ds *DbftService) CreateBookkeepingTransaction(nonce uint64) *tx.Transactio bookKeepingPayload := &payload.BookKeeping{ Nonce: uint64(time.Now().UnixNano()), } - return &tx.Transaction{ - TxType: tx.BookKeeping, - PayloadVersion: payload.BookKeepingPayloadVersion, - Payload: bookKeepingPayload, - Attributes: []*tx.TxAttribute{}, - UTXOInputs: []*tx.UTXOTxInput{}, - BalanceInputs: []*tx.BalanceTxInput{}, - Outputs: []*tx.TxOutput{}, - Programs: []*program.Program{}, + + trans := &tx.Transaction{ + TxType: tx.BookKeeping, + Payload: bookKeepingPayload, + Attributes: []*tx.TxAttribute{}, + UTXOInputs: []*tx.UTXOTxInput{}, + BalanceInputs: []*tx.BalanceTxInput{}, + Outputs: []*tx.TxOutput{}, + Programs: []*program.Program{}, } + trans.SetPayloadVersion(payload.BookKeepingPayloadVersion) + + return trans } func (ds *DbftService) ChangeViewReceived(payload *msg.ConsensusPayload, message *ChangeView) { diff --git a/core/ledger/block.go b/core/ledger/block.go index 7a581439..2e39f131 100644 --- a/core/ledger/block.go +++ b/core/ledger/block.go @@ -169,8 +169,7 @@ func GenesisBlockInit(defaultBookKeeper []*crypto.PubKey) (*Block, error) { } //transaction trans := &tx.Transaction{ - TxType: tx.BookKeeping, - PayloadVersion: payload.BookKeepingPayloadVersion, + TxType: tx.BookKeeping, Payload: &payload.BookKeeping{ Nonce: GenesisNonce, }, @@ -180,6 +179,7 @@ func GenesisBlockInit(defaultBookKeeper []*crypto.PubKey) (*Block, error) { Outputs: []*tx.TxOutput{}, Programs: []*program.Program{}, } + trans.SetPayloadVersion(payload.BookKeepingPayloadVersion) //block genesisBlock := &Block{ Blockdata: genesisBlockdata, diff --git a/core/transaction/transaction.go b/core/transaction/transaction.go index 2e3db2cc..0e7e14a1 100644 --- a/core/transaction/transaction.go +++ b/core/transaction/transaction.go @@ -2,6 +2,7 @@ package transaction import ( . "DNA/common" + "DNA/common/log" "DNA/common/serialization" "DNA/core/contract" "DNA/core/contract/program" @@ -49,14 +50,15 @@ type Payload interface { var TxStore ILedgerStore type Transaction struct { - TxType TransactionType - PayloadVersion byte - Payload Payload - Attributes []*TxAttribute - UTXOInputs []*UTXOTxInput - BalanceInputs []*BalanceTxInput - Outputs []*TxOutput - Programs []*program.Program + TxType TransactionType + version byte // first 4 bits as transaction version, left bits as payloadversion + Payload Payload + Attributes []*TxAttribute + UTXOInputs []*UTXOTxInput + BalanceInputs []*BalanceTxInput + Outputs []*TxOutput + CurrBlockHeight uint32 // added at transaction version 1 + Programs []*program.Program //Inputs/Outputs map base on Asset (needn't serialize) AssetOutputs map[Uint256][]*TxOutput @@ -66,6 +68,29 @@ type Transaction struct { hash *Uint256 } +func (tx *Transaction) GetPayloadVersion() byte { + return tx.version & 0x0f +} + +func (tx *Transaction) GetTransactionVersion() byte { + return tx.version >> 4 +} + +func (tx *Transaction) SetPayloadVersion(version byte) { + if version > 0x0f { + log.Error("Transation: wrong version number", version) + return + } + tx.version |= version +} +func (tx *Transaction) SetTransactionVersion(version byte) { + if version > 0x0f { + log.Error("Transation: wrong version number", version) + return + } + tx.version |= (version << 4) +} + //Serialize the Transaction func (tx *Transaction) Serialize(w io.Writer) error { @@ -95,12 +120,12 @@ func (tx *Transaction) SerializeUnsigned(w io.Writer) error { //txType w.Write([]byte{byte(tx.TxType)}) //PayloadVersion - w.Write([]byte{tx.PayloadVersion}) + w.Write([]byte{tx.version}) //Payload if tx.Payload == nil { return errors.New("Transaction Payload is nil.") } - tx.Payload.Serialize(w, tx.PayloadVersion) + tx.Payload.Serialize(w, tx.GetPayloadVersion()) //[]*txAttribute err := serialization.WriteVarUint(w, uint64(len(tx.Attributes))) if err != nil { @@ -133,6 +158,13 @@ func (tx *Transaction) SerializeUnsigned(w io.Writer) error { } } + if tx.GetTransactionVersion() >= 1 { + err = serialization.WriteUint32(w, tx.CurrBlockHeight) + if err != nil { + return NewDetailErr(err, ErrNoCode, "Transaction CurrBlockHeight serialization failed.") + } + } + return nil } @@ -173,9 +205,9 @@ func (tx *Transaction) DeserializeUnsigned(r io.Reader) error { } func (tx *Transaction) DeserializeUnsignedWithoutType(r io.Reader) error { - var payloadVersion [1]byte - _, err := io.ReadFull(r, payloadVersion[:]) - tx.PayloadVersion = payloadVersion[0] + var version [1]byte + _, err := io.ReadFull(r, version[:]) + tx.version = version[0] if err != nil { return err } @@ -202,7 +234,7 @@ func (tx *Transaction) DeserializeUnsignedWithoutType(r io.Reader) error { default: return errors.New("[Transaction],invalide transaction type.") } - err = tx.Payload.Deserialize(r, tx.PayloadVersion) + err = tx.Payload.Deserialize(r, tx.GetPayloadVersion()) if err != nil { return NewDetailErr(err, ErrNoCode, "Payload Parse error") } @@ -250,6 +282,14 @@ func (tx *Transaction) DeserializeUnsignedWithoutType(r io.Reader) error { tx.Outputs = append(tx.Outputs, output) } } + + if tx.GetTransactionVersion() >= 1 { + tx.CurrBlockHeight, err = serialization.ReadUint32(r) + if err != nil { + return err + } + } + return nil } diff --git a/core/validation/txValidator.go b/core/validation/txValidator.go index 24603dfd..8511270f 100644 --- a/core/validation/txValidator.go +++ b/core/validation/txValidator.go @@ -50,6 +50,22 @@ func VerifyTransaction(Tx *tx.Transaction) ErrCode { return ErrNoError } +func VerifyTransactionExpiration(Tx *tx.Transaction, validInterval, blockHeight uint32) ErrCode { + if Tx.GetTransactionVersion() == 0 { + return ErrNoError + } + + if Tx.CurrBlockHeight >= blockHeight { + return ErrTooEarly + } + + if Tx.CurrBlockHeight+validInterval < blockHeight { + return ErrExpired + } + + return ErrNoError +} + // VerifyTransactionWithBlock verifys a transaction with current transaction pool in memory func VerifyTransactionWithBlock(TxPool []*tx.Transaction) error { //initial diff --git a/errors/errcode.go b/errors/errcode.go index 3eca6724..3abfc7d6 100644 --- a/errors/errcode.go +++ b/errors/errcode.go @@ -26,6 +26,8 @@ const ( ErrStateUpdaterVaild ErrCode = 45011 ErrSummaryAsset ErrCode = 45012 ErrXmitFail ErrCode = 45013 + ErrTooEarly ErrCode = 45014 + ErrExpired ErrCode = 45015 ) func (err ErrCode) Error() string { @@ -38,7 +40,10 @@ func (err ErrCode) Error() string { return "Unknown error" case ErrDuplicatedTx: return "There are duplicated Transactions" - + case ErrTooEarly: + return "Too early to be packed in the block" + case ErrExpired: + return "Expired" } return fmt.Sprintf("Unknown error? Error code = %d", err) diff --git a/net/httpjsonrpc/common.go b/net/httpjsonrpc/common.go index ac3fde0b..ea92980b 100644 --- a/net/httpjsonrpc/common.go +++ b/net/httpjsonrpc/common.go @@ -71,14 +71,16 @@ type ProgramInfo struct { } type Transactions struct { - TxType TransactionType - PayloadVersion byte - Payload PayloadInfo - Attributes []TxAttributeInfo - UTXOInputs []UTXOTxInputInfo - BalanceInputs []BalanceTxInputInfo - Outputs []TxoutputInfo - Programs []ProgramInfo + TxType TransactionType + TransactionVersion byte + PayloadVersion byte + Payload PayloadInfo + Attributes []TxAttributeInfo + UTXOInputs []UTXOTxInputInfo + BalanceInputs []BalanceTxInputInfo + Outputs []TxoutputInfo + CurrBlockHeight uint32 + Programs []ProgramInfo AssetOutputs []TxoutputMap AssetInputAmount []AmountMap diff --git a/net/httpjsonrpc/interfaces.go b/net/httpjsonrpc/interfaces.go index 40136e0e..ae3889fd 100644 --- a/net/httpjsonrpc/interfaces.go +++ b/net/httpjsonrpc/interfaces.go @@ -26,7 +26,9 @@ func TransArryByteToHexString(ptx *tx.Transaction) *Transactions { trans := new(Transactions) trans.TxType = ptx.TxType - trans.PayloadVersion = ptx.PayloadVersion + trans.PayloadVersion = ptx.GetPayloadVersion() + trans.TransactionVersion = ptx.GetTransactionVersion() + trans.CurrBlockHeight = ptx.CurrBlockHeight trans.Payload = TransPayloadToHex(ptx.Payload) n := 0 From a9a78bf388f443e495c903b9a84327a2d7d4c1aa Mon Sep 17 00:00:00 2001 From: laizy Date: Thu, 21 Sep 2017 18:10:55 +0800 Subject: [PATCH 2/4] add txValidInterval add txValidInterval option in config and chainstore Signed-off-by: laizy --- common/config/config.go | 1 + config.json | 1 + core/ledger/blockchain.go | 4 +-- core/ledger/ledgerStore.go | 4 ++- core/store/ChainStore/ChainStore.go | 31 +++++++++++++++++++++--- core/store/ChainStore/DataEntryPrefix.go | 1 + errors/errcode.go | 3 +++ main.go | 5 ++-- net/node/transactionPool.go | 12 +++++++++ 9 files changed, 52 insertions(+), 10 deletions(-) diff --git a/common/config/config.go b/common/config/config.go index 6cf03ede..234c86a5 100644 --- a/common/config/config.go +++ b/common/config/config.go @@ -19,6 +19,7 @@ type Configuration struct { Version int `json:"Version"` SeedList []string `json:"SeedList"` BookKeepers []string `json:"BookKeepers"` // The default book keepers' publickey + TxValidInterval uint32 `json:TxValidInterval` HttpRestPort int `json:"HttpRestPort"` RestCertPath string `json:"RestCertPath"` RestKeyPath string `json:"RestKeyPath"` diff --git a/config.json b/config.json index 53e186ee..84659368 100644 --- a/config.json +++ b/config.json @@ -16,6 +16,7 @@ "032c842494feba4e3dec3b9b7d9ad080ce63c81a41f7d79d2bbb5d499d16322907", "03d36828a99547184452276116f1b5171861931ff439a6da2316fddf1f3f428850" ], + "TxValidInterval": 50, "HttpInfoPort": 20333, "HttpInfoStart": true, "HttpRestPort": 20334, diff --git a/core/ledger/blockchain.go b/core/ledger/blockchain.go index 1269d4c1..1bdb2121 100644 --- a/core/ledger/blockchain.go +++ b/core/ledger/blockchain.go @@ -23,7 +23,7 @@ func NewBlockchain(height uint32) *Blockchain { } } -func NewBlockchainWithGenesisBlock(defaultBookKeeper []*crypto.PubKey) (*Blockchain, error) { +func NewBlockchainWithGenesisBlock(defaultBookKeeper []*crypto.PubKey, txValidinterval uint32) (*Blockchain, error) { genesisBlock, err := GenesisBlockInit(defaultBookKeeper) if err != nil { return nil, NewDetailErr(err, ErrNoCode, "[Blockchain], NewBlockchainWithGenesisBlock failed.") @@ -32,7 +32,7 @@ func NewBlockchainWithGenesisBlock(defaultBookKeeper []*crypto.PubKey) (*Blockch hashx := genesisBlock.Hash() genesisBlock.hash = &hashx - height, err := DefaultLedger.Store.InitLedgerStoreWithGenesisBlock(genesisBlock, defaultBookKeeper) + height, err := DefaultLedger.Store.InitLedgerStoreWithGenesisBlock(genesisBlock, defaultBookKeeper, txValidinterval) if err != nil { return nil, NewDetailErr(err, ErrNoCode, "[Blockchain], InitLevelDBStoreWithGenesisBlock failed.") } diff --git a/core/ledger/ledgerStore.go b/core/ledger/ledgerStore.go index fa67277c..ee45aa2a 100644 --- a/core/ledger/ledgerStore.go +++ b/core/ledger/ledgerStore.go @@ -36,7 +36,9 @@ type ILedgerStore interface { GetHeaderHashByHeight(height uint32) Uint256 GetBookKeeperList() ([]*crypto.PubKey, []*crypto.PubKey, error) - InitLedgerStoreWithGenesisBlock(genesisblock *Block, defaultBookKeeper []*crypto.PubKey) (uint32, error) + GetTxValidInterval() (uint32, error) + + InitLedgerStoreWithGenesisBlock(genesisBlock *Block, defaultBookKeeper []*crypto.PubKey, txValidInterval uint32) (uint32, error) GetQuantityIssued(assetid Uint256) (Fixed64, error) diff --git a/core/store/ChainStore/ChainStore.go b/core/store/ChainStore/ChainStore.go index 7fc00587..0864304f 100644 --- a/core/store/ChainStore/ChainStore.go +++ b/core/store/ChainStore/ChainStore.go @@ -25,9 +25,10 @@ import ( ) const ( - HeaderHashListCount = 2000 - CleanCacheThreshold = 2 - TaskChanCap = 4 + HeaderHashListCount = 2000 + CleanCacheThreshold = 2 + TaskChanCap = 4 + DefaultTxValidInterval = 50 ) var ( @@ -149,7 +150,10 @@ func (self *ChainStore) clearCache() { } -func (bd *ChainStore) InitLedgerStoreWithGenesisBlock(genesisBlock *Block, defaultBookKeeper []*crypto.PubKey) (uint32, error) { +func (bd *ChainStore) InitLedgerStoreWithGenesisBlock(genesisBlock *Block, defaultBookKeeper []*crypto.PubKey, txValidInterval uint32) (uint32, error) { + if txValidInterval == 0 { + txValidInterval = DefaultTxValidInterval + } hash := genesisBlock.Hash() bd.headerIndex[0] = hash @@ -289,6 +293,10 @@ func (bd *ChainStore) InitLedgerStoreWithGenesisBlock(genesisBlock *Block, defau bd.st.Put(bkListKey.Bytes(), bkListValue.Bytes()) /////////////////////////////////////////////////// + tvi := bytes.NewBuffer(nil) + serialization.WriteUint32(tvi, txValidInterval) + bd.st.Put([]byte{byte(SYS_TxValidInterval)}, tvi.Bytes()) + // persist genesis block bd.persist(genesisBlock) @@ -629,6 +637,21 @@ func (bd *ChainStore) GetBlock(hash Uint256) (*Block, error) { return b, nil } +func (self *ChainStore) GetTxValidInterval() (uint32, error) { + prefix := []byte{byte(SYS_TxValidInterval)} + tvi, err := self.st.Get(prefix) + if err != nil { + return 0, err + } + + txValidInterval, err := serialization.ReadUint32(bytes.NewReader(tvi)) + if err != nil { + return 0, err + } + + return txValidInterval, nil +} + func (self *ChainStore) GetBookKeeperList() ([]*crypto.PubKey, []*crypto.PubKey, error) { prefix := []byte{byte(SYS_CurrentBookKeeper)} bkListValue, err_get := self.st.Get(prefix) diff --git a/core/store/ChainStore/DataEntryPrefix.go b/core/store/ChainStore/DataEntryPrefix.go index c9ba92d8..087da928 100644 --- a/core/store/ChainStore/DataEntryPrefix.go +++ b/core/store/ChainStore/DataEntryPrefix.go @@ -26,6 +26,7 @@ const ( SYS_CurrentBlock DataEntryPrefix = 0x40 // SYS_CurrentHeader DataEntryPrefix = 0x41 SYS_CurrentBookKeeper DataEntryPrefix = 0x42 + SYS_TxValidInterval DataEntryPrefix = 0x43 //CONFIG CFG_Version DataEntryPrefix = 0xf0 diff --git a/errors/errcode.go b/errors/errcode.go index 3abfc7d6..d4d2de12 100644 --- a/errors/errcode.go +++ b/errors/errcode.go @@ -28,6 +28,7 @@ const ( ErrXmitFail ErrCode = 45013 ErrTooEarly ErrCode = 45014 ErrExpired ErrCode = 45015 + ErrInternal ErrCode = 45016 ) func (err ErrCode) Error() string { @@ -44,6 +45,8 @@ func (err ErrCode) Error() string { return "Too early to be packed in the block" case ErrExpired: return "Expired" + case ErrInternal: + return "Internal error" } return fmt.Sprintf("Unknown error? Error code = %d", err) diff --git a/main.go b/main.go index cf701124..e5c7ff47 100644 --- a/main.go +++ b/main.go @@ -11,9 +11,9 @@ import ( "DNA/crypto" "DNA/net" "DNA/net/httpjsonrpc" + "DNA/net/httpnodeinfo" "DNA/net/httprestful" "DNA/net/httpwebsocket" - "DNA/net/httpnodeinfo" "DNA/net/protocol" "os" "runtime" @@ -75,7 +75,7 @@ func main() { ledger.StandbyBookKeepers = account.GetBookKeepers() log.Info("3. BlockChain init") - blockChain, err = ledger.NewBlockchainWithGenesisBlock(ledger.StandbyBookKeepers) + blockChain, err = ledger.NewBlockchainWithGenesisBlock(ledger.StandbyBookKeepers, config.Parameters.TxValidInterval) if err != nil { log.Fatal(err, " BlockChain generate failed") goto ERROR @@ -107,7 +107,6 @@ func main() { go httpnodeinfo.StartServer(noder) } - for { time.Sleep(dbft.GenBlockTime) log.Trace("BlockHeight = ", ledger.DefaultLedger.Blockchain.BlockHeight) diff --git a/net/node/transactionPool.go b/net/node/transactionPool.go index 0fe57802..0c39bf06 100644 --- a/net/node/transactionPool.go +++ b/net/node/transactionPool.go @@ -33,6 +33,18 @@ func (this *TXNPool) init() { //append transaction to txnpool when check ok. //1.check transaction. 2.check with ledger(db) 3.check with pool func (this *TXNPool) AppendTxnPool(txn *transaction.Transaction) ErrCode { + if txn.GetTransactionVersion() >= 1 { + blockHeight := ledger.DefaultLedger.Blockchain.BlockHeight + validInterval, err := ledger.DefaultLedger.Store.GetTxValidInterval() + if err != nil { + log.Error("Can not get TxValidInterval from DB, ", err) + return ErrInternal + } + if errCode := va.VerifyTransactionExpiration(txn, validInterval, blockHeight+1); errCode != ErrNoError { + log.Info("Transaction verification failed", txn.Hash()) + return errCode + } + } //verify transaction with Concurrency if errCode := va.VerifyTransaction(txn); errCode != ErrNoError { log.Info("Transaction verification failed", txn.Hash()) From ab47ba51b99b7013484ed21ddad6e384f4c5179a Mon Sep 17 00:00:00 2001 From: laizy Date: Fri, 22 Sep 2017 11:19:51 +0800 Subject: [PATCH 3/4] add check in GetTxnPool function Signed-off-by: laizy --- consensus/dbft/dbftService.go | 4 +++- net/net.go | 3 +-- net/node/transactionPool.go | 26 +++++++++++++++++++++----- net/protocol/protocol.go | 3 +-- 4 files changed, 26 insertions(+), 10 deletions(-) diff --git a/consensus/dbft/dbftService.go b/consensus/dbft/dbftService.go index 0aa5c0f5..8e98b876 100644 --- a/consensus/dbft/dbftService.go +++ b/consensus/dbft/dbftService.go @@ -67,7 +67,7 @@ func (ds *DbftService) BlockPersistCompleted(v interface{}) { log.Debug() if block, ok := v.(*ledger.Block); ok { log.Infof("persist block: %x", block.Hash()) - err := ds.localNet.CleanSubmittedTransactions(block) + err := ds.localNet.CleanSubmittedTransactions(block.Transactions) if err != nil { log.Warn(err) } @@ -557,9 +557,11 @@ func (ds *DbftService) Timeout() { //add book keeping transaction first ds.context.Transactions = append(ds.context.Transactions, txBookkeeping) //add transactions from transaction pool + for _, tx := range transactionsPool { ds.context.Transactions = append(ds.context.Transactions, tx) } + ds.context.header = nil //build block and sign block := ds.context.MakeHeader() diff --git a/net/net.go b/net/net.go index c56f4657..0f3a4002 100644 --- a/net/net.go +++ b/net/net.go @@ -2,7 +2,6 @@ package net import ( . "DNA/common" - "DNA/core/ledger" "DNA/core/transaction" "DNA/crypto" . "DNA/errors" @@ -16,7 +15,7 @@ type Neter interface { Xmit(interface{}) error GetEvent(eventName string) *events.Event GetBookKeepersAddrs() ([]*crypto.PubKey, uint64) - CleanSubmittedTransactions(block *ledger.Block) error + CleanSubmittedTransactions(txs []*transaction.Transaction) error GetNeighborNoder() []protocol.Noder Tx(buf []byte) AppendTxnPool(*transaction.Transaction) ErrCode diff --git a/net/node/transactionPool.go b/net/node/transactionPool.go index 0c39bf06..add24b6d 100644 --- a/net/node/transactionPool.go +++ b/net/node/transactionPool.go @@ -41,7 +41,7 @@ func (this *TXNPool) AppendTxnPool(txn *transaction.Transaction) ErrCode { return ErrInternal } if errCode := va.VerifyTransactionExpiration(txn, validInterval, blockHeight+1); errCode != ErrNoError { - log.Info("Transaction verification failed", txn.Hash()) + log.Warn("Transaction verification failed", txn.Hash()) return errCode } } @@ -75,22 +75,38 @@ func (this *TXNPool) GetTxnPool(byCount bool) map[common.Uint256]*transaction.Tr } var num int txnMap := make(map[common.Uint256]*transaction.Transaction, count) + interval, _ := ledger.DefaultLedger.Store.GetTxValidInterval() + expired := make([]*transaction.Transaction, 0) + height := ledger.DefaultLedger.Blockchain.BlockHeight + 1 for txnId, tx := range this.txnList { + if tx.GetTransactionVersion() >= 1 { + if errCode := va.VerifyTransactionExpiration(tx, interval, height); errCode != ErrNoError { + if errCode == ErrExpired { + expired = append(expired, tx) + } + continue + } + } txnMap[txnId] = tx num++ if num >= count { break } } + this.RUnlock() + if len(expired) > 0 { + log.Info("Got expired transactions:", len(expired)) + this.CleanSubmittedTransactions(expired) + } return txnMap } //clean the trasaction Pool with committed block. -func (this *TXNPool) CleanSubmittedTransactions(block *ledger.Block) error { - this.cleanTransactionList(block.Transactions) - this.cleanUTXOList(block.Transactions) - this.cleanIssueSummary(block.Transactions) +func (this *TXNPool) CleanSubmittedTransactions(txs []*transaction.Transaction) error { + this.cleanTransactionList(txs) + this.cleanUTXOList(txs) + this.cleanIssueSummary(txs) return nil } diff --git a/net/protocol/protocol.go b/net/protocol/protocol.go index 9aacb483..321cfa80 100644 --- a/net/protocol/protocol.go +++ b/net/protocol/protocol.go @@ -2,7 +2,6 @@ package protocol import ( "DNA/common" - "DNA/core/ledger" "DNA/core/transaction" "DNA/crypto" . "DNA/errors" @@ -119,7 +118,7 @@ type Noder interface { SetBookKeeperAddr(pk *crypto.PubKey) GetNeighborHeights() ([]uint64, uint64) SyncNodeHeight() - CleanSubmittedTransactions(block *ledger.Block) error + CleanSubmittedTransactions(txs []*transaction.Transaction) error GetNeighborNoder() []Noder GetNbrNodeCnt() uint32 From 42ebde95a6aedd83cda95ad6226c49dd170f7b1b Mon Sep 17 00:00:00 2001 From: laizy Date: Fri, 22 Sep 2017 16:52:36 +0800 Subject: [PATCH 4/4] add currBlockheight in cli and transaction construction Signed-off-by: laizy --- cli/asset/asset.go | 23 +++- cli/bookkeeper/bookkeeper.go | 7 +- cli/common/common.go | 20 ++++ cli/data/data.go | 7 +- cli/privpayload/privpayload.go | 7 +- cli/test/test.go | 6 +- core/transaction/TransactionBuilder.go | 155 ++++++++++++++----------- net/httpjsonrpc/RPCserver.go | 1 + net/httpjsonrpc/common.go | 2 +- net/httpjsonrpc/interfaces.go | 9 +- net/httpjsonrpc/sampleTransaction.go | 4 +- net/httprestful/common/custom.go | 7 +- net/node/transactionPool.go | 4 +- 13 files changed, 164 insertions(+), 88 deletions(-) diff --git a/cli/asset/asset.go b/cli/asset/asset.go index df00e22a..3ec5a349 100644 --- a/cli/asset/asset.go +++ b/cli/asset/asset.go @@ -97,7 +97,12 @@ func makeRegTransaction(admin, issuer *account.Account, name string, description fmt.Println("CreateSignatureContract failed") return "", err } - tx, _ := transaction.NewRegisterAssetTransaction(asset, value, issuer.PubKey(), transactionContract.ProgramHash) + height, err := GetCurrBlockHeight() + if err != nil { + fmt.Println("Can not get currBlockHeight", err) + return "", err + } + tx, _ := transaction.NewRegisterAssetTransaction(asset, value, issuer.PubKey(), transactionContract.ProgramHash, height) txAttr := transaction.NewTxAttribute(transaction.Nonce, []byte(strconv.FormatInt(rand.Int63(), 10))) tx.Attributes = make([]*transaction.TxAttribute, 0) tx.Attributes = append(tx.Attributes, &txAttr) @@ -124,7 +129,12 @@ func makeIssueTransaction(issuer *account.Account, programHashStr, assetHashStr ProgramHash: programHash, } outputs := []*transaction.TxOutput{issueTxOutput} - tx, _ := transaction.NewIssueAssetTransaction(outputs) + height, err := GetCurrBlockHeight() + if err != nil { + fmt.Println("Can not get currBlockHeight", err) + return "", err + } + tx, _ := transaction.NewIssueAssetTransaction(outputs, height) txAttr := transaction.NewTxAttribute(transaction.Nonce, []byte(strconv.FormatInt(rand.Int63(), 10))) tx.Attributes = make([]*transaction.TxAttribute, 0) tx.Attributes = append(tx.Attributes, &txAttr) @@ -217,7 +227,12 @@ func makeTransferTransaction(signer *account.Account, programHashStr, assetHashS if expected != 0 { return "", errors.New("transfer failed, ammount is not enough") } - tx, _ := transaction.NewTransferAssetTransaction(inputs, outputs) + height, err := GetCurrBlockHeight() + if err != nil { + fmt.Println("Can not get currBlockHeight", err) + return "", err + } + tx, _ := transaction.NewTransferAssetTransaction(inputs, outputs, height) txAttr := transaction.NewTxAttribute(transaction.Nonce, []byte(strconv.FormatInt(rand.Int63(), 10))) tx.Attributes = make([]*transaction.TxAttribute, 0) tx.Attributes = append(tx.Attributes, &txAttr) @@ -248,6 +263,7 @@ func assetAction(c *cli.Context) error { wallet := openWallet(c.String("wallet"), WalletPassword(c.String("password"))) admin, _ := wallet.GetDefaultAccount() + value := c.Int64("value") if value == 0 { fmt.Println("invalid value [--value]") @@ -294,6 +310,7 @@ func assetAction(c *cli.Context) error { } func NewCommand() *cli.Command { + return &cli.Command{ Name: "asset", Usage: "asset registration, issuance and transfer", diff --git a/cli/bookkeeper/bookkeeper.go b/cli/bookkeeper/bookkeeper.go index bbd31ad7..523b8576 100644 --- a/cli/bookkeeper/bookkeeper.go +++ b/cli/bookkeeper/bookkeeper.go @@ -19,7 +19,12 @@ import ( ) func makeBookkeeperTransaction(pubkey *crypto.PubKey, op bool, cert []byte, issuer *account.Account) (string, error) { - tx, _ := transaction.NewBookKeeperTransaction(pubkey, op, cert, issuer.PubKey()) + height, err := GetCurrBlockHeight() + if err != nil { + fmt.Println("Can not get currBlockHeight", err) + return "", err + } + tx, _ := transaction.NewBookKeeperTransaction(pubkey, op, cert, issuer.PubKey(), height) attr := transaction.NewTxAttribute(transaction.Nonce, []byte(strconv.FormatInt(rand.Int63(), 10))) tx.Attributes = make([]*transaction.TxAttribute, 0) tx.Attributes = append(tx.Attributes, &attr) diff --git a/cli/common/common.go b/cli/common/common.go index e706304b..81bde8c9 100644 --- a/cli/common/common.go +++ b/cli/common/common.go @@ -9,6 +9,7 @@ import ( "DNA/common/config" "DNA/common/password" + "DNA/net/httpjsonrpc" "github.com/urfave/cli" ) @@ -69,3 +70,22 @@ func WalletPassword(passwd string) []byte { return []byte(passwd) } } + +func GetCurrBlockHeight() (uint32, error) { + resp, err := httpjsonrpc.Call(Address(), "getbestblockheight", 0, []interface{}{}) + + if err != nil { + fmt.Println("HTTP JSON call failed", err) + return 0, err + } + r := make(map[string]interface{}) + err = json.Unmarshal(resp, &r) + if err != nil { + fmt.Println("Unmarshal JSON failed") + return 0, err + } + + height := r["result"].(float64) + + return uint32(height), nil +} diff --git a/cli/data/data.go b/cli/data/data.go index b640274e..21df6c37 100644 --- a/cli/data/data.go +++ b/cli/data/data.go @@ -149,7 +149,12 @@ func dataAction(c *cli.Context) error { wallet := openWallet(c.String("wallet"), WalletPassword(c.String("password"))) admin, _ := wallet.GetDefaultAccount() - tx, _ = transaction.NewDataFileTransaction(address, name, "", admin.PubKey()) + height, err := GetCurrBlockHeight() + if err != nil { + fmt.Println("Can not get currBlockHeight", err) + return err + } + tx, _ = transaction.NewDataFileTransaction(address, name, "", admin.PubKey(), height) txAttr := transaction.NewTxAttribute(transaction.Nonce, []byte(strconv.FormatInt(rand.Int63(), 10))) tx.Attributes = make([]*transaction.TxAttribute, 0) tx.Attributes = append(tx.Attributes, &txAttr) diff --git a/cli/privpayload/privpayload.go b/cli/privpayload/privpayload.go index 41b19a5d..c75cc1a9 100644 --- a/cli/privpayload/privpayload.go +++ b/cli/privpayload/privpayload.go @@ -27,7 +27,12 @@ func makePrivacyTx(admin *account.Account, toPubkeyStr string, pload string) (st toPk, _ := hex.DecodeString(toPubkeyStr) toPubkey, _ := crypto.DecodePoint(toPk) - tx, _ := transaction.NewPrivacyPayloadTransaction(admin.PrivateKey, admin.PublicKey, toPubkey, payload.RawPayload, data) + height, err := GetCurrBlockHeight() + if err != nil { + fmt.Println("Can not get currBlockHeight", err) + return "", err + } + tx, _ := transaction.NewPrivacyPayloadTransaction(admin.PrivateKey, admin.PublicKey, toPubkey, payload.RawPayload, data, height) txAttr := transaction.NewTxAttribute(transaction.Nonce, []byte(strconv.FormatInt(rand.Int63(), 10))) tx.Attributes = make([]*transaction.TxAttribute, 0) tx.Attributes = append(tx.Attributes, &txAttr) diff --git a/cli/test/test.go b/cli/test/test.go index 472ff5c7..6c4a933f 100644 --- a/cli/test/test.go +++ b/cli/test/test.go @@ -1,13 +1,11 @@ package test import ( - "fmt" - "os" - . "DNA/cli/common" "DNA/net/httpjsonrpc" - + "fmt" "github.com/urfave/cli" + "os" ) func testAction(c *cli.Context) (err error) { diff --git a/core/transaction/TransactionBuilder.go b/core/transaction/TransactionBuilder.go index a181e850..8ee7b415 100644 --- a/core/transaction/TransactionBuilder.go +++ b/core/transaction/TransactionBuilder.go @@ -9,7 +9,7 @@ import ( ) //initial a new transaction with asset registration payload -func NewRegisterAssetTransaction(asset *asset.Asset, amount common.Fixed64, issuer *crypto.PubKey, conroller common.Uint160) (*Transaction, error) { +func NewRegisterAssetTransaction(asset *asset.Asset, amount common.Fixed64, issuer *crypto.PubKey, conroller common.Uint160, height uint32) (*Transaction, error) { //TODO: check arguments @@ -21,19 +21,22 @@ func NewRegisterAssetTransaction(asset *asset.Asset, amount common.Fixed64, issu Controller: conroller, } - return &Transaction{ + tx := &Transaction{ //nonce uint64 //TODO: genenrate nonce - UTXOInputs: []*UTXOTxInput{}, - BalanceInputs: []*BalanceTxInput{}, - Attributes: []*TxAttribute{}, - TxType: RegisterAsset, - Payload: assetRegPayload, - Programs: []*program.Program{}, - }, nil + UTXOInputs: []*UTXOTxInput{}, + BalanceInputs: []*BalanceTxInput{}, + Attributes: []*TxAttribute{}, + TxType: RegisterAsset, + Payload: assetRegPayload, + Programs: []*program.Program{}, + CurrBlockHeight: height, + } + tx.SetTransactionVersion(1) + return tx, nil } //initial a new transaction with asset registration payload -func NewBookKeeperTransaction(pubKey *crypto.PubKey, isAdd bool, cert []byte, issuer *crypto.PubKey) (*Transaction, error) { +func NewBookKeeperTransaction(pubKey *crypto.PubKey, isAdd bool, cert []byte, issuer *crypto.PubKey, height uint32) (*Transaction, error) { bookKeeperPayload := &payload.BookKeeper{ PubKey: pubKey, @@ -46,66 +49,72 @@ func NewBookKeeperTransaction(pubKey *crypto.PubKey, isAdd bool, cert []byte, is bookKeeperPayload.Action = payload.BookKeeperAction_ADD } - return &Transaction{ - TxType: BookKeeper, - Payload: bookKeeperPayload, - UTXOInputs: []*UTXOTxInput{}, - BalanceInputs: []*BalanceTxInput{}, - Attributes: []*TxAttribute{}, - Programs: []*program.Program{}, - }, nil + tx := &Transaction{ + TxType: BookKeeper, + Payload: bookKeeperPayload, + UTXOInputs: []*UTXOTxInput{}, + BalanceInputs: []*BalanceTxInput{}, + Attributes: []*TxAttribute{}, + Programs: []*program.Program{}, + CurrBlockHeight: height, + } + tx.SetTransactionVersion(1) + return tx, nil } -func NewIssueAssetTransaction(outputs []*TxOutput) (*Transaction, error) { - +func NewIssueAssetTransaction(outputs []*TxOutput, height uint32) (*Transaction, error) { assetRegPayload := &payload.IssueAsset{} - return &Transaction{ - TxType: IssueAsset, - Payload: assetRegPayload, - Attributes: []*TxAttribute{}, - BalanceInputs: []*BalanceTxInput{}, - Outputs: outputs, - Programs: []*program.Program{}, - }, nil + tx := &Transaction{ + TxType: IssueAsset, + Payload: assetRegPayload, + Attributes: []*TxAttribute{}, + BalanceInputs: []*BalanceTxInput{}, + Outputs: outputs, + Programs: []*program.Program{}, + CurrBlockHeight: height, + } + tx.SetTransactionVersion(1) + return tx, nil } -func NewTransferAssetTransaction(inputs []*UTXOTxInput, outputs []*TxOutput) (*Transaction, error) { - - //TODO: check arguments - +func NewTransferAssetTransaction(inputs []*UTXOTxInput, outputs []*TxOutput, height uint32) (*Transaction, error) { assetRegPayload := &payload.TransferAsset{} - return &Transaction{ - TxType: TransferAsset, - Payload: assetRegPayload, - Attributes: []*TxAttribute{}, - UTXOInputs: inputs, - BalanceInputs: []*BalanceTxInput{}, - Outputs: outputs, - Programs: []*program.Program{}, - }, nil + tx := &Transaction{ + TxType: TransferAsset, + Payload: assetRegPayload, + Attributes: []*TxAttribute{}, + UTXOInputs: inputs, + BalanceInputs: []*BalanceTxInput{}, + Outputs: outputs, + Programs: []*program.Program{}, + CurrBlockHeight: height, + } + tx.SetTransactionVersion(1) + return tx, nil } -//initial a new transaction with record payload -func NewRecordTransaction(recordType string, recordData []byte) (*Transaction, error) { - //TODO: check arguments +func NewRecordTransaction(recordType string, recordData []byte, height uint32) (*Transaction, error) { recordPayload := &payload.Record{ RecordType: recordType, RecordData: recordData, } - return &Transaction{ - TxType: Record, - Payload: recordPayload, - Attributes: []*TxAttribute{}, - UTXOInputs: []*UTXOTxInput{}, - BalanceInputs: []*BalanceTxInput{}, - Programs: []*program.Program{}, - }, nil + tx := &Transaction{ + TxType: Record, + Payload: recordPayload, + Attributes: []*TxAttribute{}, + UTXOInputs: []*UTXOTxInput{}, + BalanceInputs: []*BalanceTxInput{}, + Programs: []*program.Program{}, + CurrBlockHeight: height, + } + tx.SetTransactionVersion(1) + return tx, nil } -func NewPrivacyPayloadTransaction(fromPrivKey []byte, fromPubkey *crypto.PubKey, toPubkey *crypto.PubKey, payloadType payload.EncryptedPayloadType, data []byte) (*Transaction, error) { +func NewPrivacyPayloadTransaction(fromPrivKey []byte, fromPubkey *crypto.PubKey, toPubkey *crypto.PubKey, payloadType payload.EncryptedPayloadType, data []byte, height uint32) (*Transaction, error) { privacyPayload := &payload.PrivacyPayload{ PayloadType: payloadType, EncryptType: payload.ECDH_AES256, @@ -116,16 +125,19 @@ func NewPrivacyPayloadTransaction(fromPrivKey []byte, fromPubkey *crypto.PubKey, } privacyPayload.Payload, _ = privacyPayload.EncryptAttr.Encrypt(data, fromPrivKey) - return &Transaction{ - TxType: PrivacyPayload, - Payload: privacyPayload, - Attributes: []*TxAttribute{}, - UTXOInputs: []*UTXOTxInput{}, - BalanceInputs: []*BalanceTxInput{}, - Programs: []*program.Program{}, - }, nil + tx := &Transaction{ + TxType: PrivacyPayload, + Payload: privacyPayload, + Attributes: []*TxAttribute{}, + UTXOInputs: []*UTXOTxInput{}, + BalanceInputs: []*BalanceTxInput{}, + Programs: []*program.Program{}, + CurrBlockHeight: height, + } + tx.SetTransactionVersion(1) + return tx, nil } -func NewDataFileTransaction(path string, fileName string, note string, issuer *crypto.PubKey) (*Transaction, error) { +func NewDataFileTransaction(path string, fileName string, note string, issuer *crypto.PubKey, height uint32) (*Transaction, error) { //TODO: check arguments DataFilePayload := &payload.DataFile{ IPFSPath: path, @@ -134,12 +146,15 @@ func NewDataFileTransaction(path string, fileName string, note string, issuer *c Issuer: issuer, } - return &Transaction{ - TxType: DataFile, - Payload: DataFilePayload, - Attributes: []*TxAttribute{}, - UTXOInputs: []*UTXOTxInput{}, - BalanceInputs: []*BalanceTxInput{}, - Programs: []*program.Program{}, - }, nil + tx := &Transaction{ + TxType: DataFile, + Payload: DataFilePayload, + Attributes: []*TxAttribute{}, + UTXOInputs: []*UTXOTxInput{}, + BalanceInputs: []*BalanceTxInput{}, + Programs: []*program.Program{}, + CurrBlockHeight: height, + } + tx.SetTransactionVersion(1) + return tx, nil } diff --git a/net/httpjsonrpc/RPCserver.go b/net/httpjsonrpc/RPCserver.go index 1075e77e..7f6c43cc 100644 --- a/net/httpjsonrpc/RPCserver.go +++ b/net/httpjsonrpc/RPCserver.go @@ -12,6 +12,7 @@ func StartRPCServer() { http.HandleFunc("/", Handle) HandleFunc("getbestblockhash", getBestBlockHash) + HandleFunc("getbestblockheight", getBestBlockHeight) HandleFunc("getblock", getBlock) HandleFunc("getblockcount", getBlockCount) HandleFunc("getblockhash", getBlockHash) diff --git a/net/httpjsonrpc/common.go b/net/httpjsonrpc/common.go index ea92980b..154783b7 100644 --- a/net/httpjsonrpc/common.go +++ b/net/httpjsonrpc/common.go @@ -275,7 +275,7 @@ func VerifyAndSendTx(txn *tx.Transaction) ErrCode { // if transaction is verified unsucessfully then will not put it into transaction pool if errCode := node.AppendTxnPool(txn); errCode != ErrNoError { log.Warn("Can NOT add the transaction to TxnPool") - log.Info("[httpjsonrpc] VerifyTransaction failed when AppendTxnPool.") + log.Info("[httpjsonrpc] VerifyTransaction failed when AppendTxnPool.", errCode.Error()) return errCode } if err := node.Xmit(txn); err != nil { diff --git a/net/httpjsonrpc/interfaces.go b/net/httpjsonrpc/interfaces.go index ae3889fd..9e775c85 100644 --- a/net/httpjsonrpc/interfaces.go +++ b/net/httpjsonrpc/interfaces.go @@ -114,11 +114,17 @@ func getCurrentDirectory() string { } return dir } + func getBestBlockHash(params []interface{}) map[string]interface{} { hash := ledger.DefaultLedger.Blockchain.CurrentBlockHash() return DnaRpc(ToHexString(hash.ToArray())) } +func getBestBlockHeight(params []interface{}) map[string]interface{} { + height := ledger.DefaultLedger.Blockchain.BlockHeight + return DnaRpc(height) +} + // Input JSON string examples for getblock method as following: // {"jsonrpc": "2.0", "method": "getblock", "params": [1], "id": 0} // {"jsonrpc": "2.0", "method": "getblock", "params": ["aabbcc.."], "id": 0} @@ -471,7 +477,8 @@ func sendSampleTransaction(params []interface{}) map[string]interface{} { } } for i := 0; i < num; i++ { - regTx := NewRegTx(ToHexString(rbuf), i, admin, issuer) + height := ledger.DefaultLedger.Blockchain.BlockHeight + regTx := NewRegTx(ToHexString(rbuf), i, admin, issuer, height) SignTx(admin, regTx) VerifyAndSendTx(regTx) } diff --git a/net/httpjsonrpc/sampleTransaction.go b/net/httpjsonrpc/sampleTransaction.go index 1c8c49eb..f049bfd9 100644 --- a/net/httpjsonrpc/sampleTransaction.go +++ b/net/httpjsonrpc/sampleTransaction.go @@ -15,13 +15,13 @@ const ( ASSETPREFIX = "DNA" ) -func NewRegTx(rand string, index int, admin, issuer *Account) *transaction.Transaction { +func NewRegTx(rand string, index int, admin, issuer *Account, height uint32) *transaction.Transaction { name := ASSETPREFIX + "-" + strconv.Itoa(index) + "-" + rand description := "description" asset := &Asset{name, description, byte(MaxPrecision), AssetType(Share), UTXO} amount := Fixed64(1000) controller, _ := contract.CreateSignatureContract(admin.PubKey()) - tx, _ := transaction.NewRegisterAssetTransaction(asset, amount, issuer.PubKey(), controller.ProgramHash) + tx, _ := transaction.NewRegisterAssetTransaction(asset, amount, issuer.PubKey(), controller.ProgramHash, height) return tx } diff --git a/net/httprestful/common/custom.go b/net/httprestful/common/custom.go index ec7bf356..c5db6139 100644 --- a/net/httprestful/common/custom.go +++ b/net/httprestful/common/custom.go @@ -2,6 +2,7 @@ package common import ( . "DNA/common" + "DNA/core/ledger" tx "DNA/core/transaction" . "DNA/errors" . "DNA/net/httpjsonrpc" @@ -89,7 +90,8 @@ func SendRecord(cmd map[string]interface{}) map[string]interface{} { var inputs []*tx.UTXOTxInput var outputs []*tx.TxOutput - transferTx, _ := tx.NewTransferAssetTransaction(inputs, outputs) + height := ledger.DefaultLedger.Blockchain.BlockHeight + transferTx, _ := tx.NewTransferAssetTransaction(inputs, outputs, height) rcdInner := tx.NewTxAttribute(tx.Description, innerTime) transferTx.Attributes = append(transferTx.Attributes, &rcdInner) @@ -124,7 +126,8 @@ func SendRecordTransaction(cmd map[string]interface{}) map[string]interface{} { return resp } recordType := "record" - recordTx, _ := tx.NewRecordTransaction(recordType, recordData) + height := ledger.DefaultLedger.Blockchain.BlockHeight + recordTx, _ := tx.NewRecordTransaction(recordType, recordData, height) hash := recordTx.Hash() resp["Result"] = ToHexString(hash.ToArrayReverse()) diff --git a/net/node/transactionPool.go b/net/node/transactionPool.go index add24b6d..5776e7f2 100644 --- a/net/node/transactionPool.go +++ b/net/node/transactionPool.go @@ -40,8 +40,8 @@ func (this *TXNPool) AppendTxnPool(txn *transaction.Transaction) ErrCode { log.Error("Can not get TxValidInterval from DB, ", err) return ErrInternal } - if errCode := va.VerifyTransactionExpiration(txn, validInterval, blockHeight+1); errCode != ErrNoError { - log.Warn("Transaction verification failed", txn.Hash()) + if errCode := va.VerifyTransactionExpiration(txn, validInterval, blockHeight+1); errCode == ErrTooEarly { + log.Warnf("Transaction expired %x", txn.Hash()) return errCode } }