• R/O
  • HTTP
  • SSH
  • HTTPS

vapor: Commit

Golang implemented sidechain for Bytom


Commit MetaInfo

Revisiona33035030d41ca431cbe7df8946a8ddb0eafd559 (tree)
Time2020-02-24 11:42:56
Authoripqhjjybj <250657661@qq.c...>
Commiteripqhjjybj

Log Message

s

Change Summary

Incremental Difference

--- a/proposal/proposal.go
+++ b/proposal/proposal.go
@@ -1,6 +1,7 @@
11 package proposal
22
33 import (
4+ "fmt"
45 "sort"
56 "strconv"
67 "time"
@@ -96,12 +97,14 @@ func (b *blockBuilder) applyCoinbaseTransaction() error {
9697 }
9798
9899 func (b *blockBuilder) applyTransactions(txs []*types.Tx, timeoutStatus uint8) error {
100+ fmt.Println("applyTransactions")
99101 tempTxs := []*types.Tx{}
100102 for i := 0; i < len(txs); i++ {
101103 if tempTxs = append(tempTxs, txs[i]); len(tempTxs) < batchApplyNum && i != len(txs)-1 {
102104 continue
103105 }
104106
107+ fmt.Println("i=", i, "preValidateTxs")
105108 results, gasLeft := preValidateTxs(tempTxs, b.chain, b.utxoView, b.gasLeft)
106109 for _, result := range results {
107110 if result.err != nil && !result.gasOnly {
@@ -242,11 +245,14 @@ func createCoinbaseTxByReward(accountManager *account.Manager, blockHeight uint6
242245 arbitrary := append([]byte{0x00}, []byte(strconv.FormatUint(blockHeight, 10))...)
243246 var script []byte
244247 if accountManager == nil {
248+ fmt.Println("accountManager == nil ")
245249 script, err = vmutil.DefaultCoinbaseProgram()
246250 } else {
247251 script, err = accountManager.GetCoinbaseControlProgram()
252+ fmt.Println("script:", script)
248253 arbitrary = append(arbitrary, accountManager.GetCoinbaseArbitrary()...)
249254 }
255+ fmt.Println("blockHeight", blockHeight, "script:", script)
250256 if err != nil {
251257 return nil, err
252258 }
--- a/protocol/block.go
+++ b/protocol/block.go
@@ -1,6 +1,8 @@
11 package protocol
22
33 import (
4+ "fmt"
5+
46 log "github.com/sirupsen/logrus"
57
68 "github.com/bytom/vapor/errors"
@@ -92,10 +94,14 @@ func (c *Chain) connectBlock(block *types.Block) (err error) {
9294 return err
9395 }
9496
97+ fmt.Println("connectBlock abcd")
9598 utxoView := state.NewUtxoViewpoint()
9699 if err := c.store.GetTransactionsUtxo(utxoView, bcBlock.Transactions); err != nil {
97100 return err
98101 }
102+
103+ fmt.Println("utxoView.ApplyBlock")
104+ //fmt.Println("bcBlock.TransactionStatus", bcBlock.TransactionStatus)
99105 if err := utxoView.ApplyBlock(bcBlock, bcBlock.TransactionStatus); err != nil {
100106 return err
101107 }
@@ -382,19 +388,23 @@ func (c *Chain) saveBlock(block *types.Block) error {
382388 }
383389
384390 bcBlock := types.MapBlock(block)
391+ fmt.Println("validation.ValidateBlock")
385392 if err := validation.ValidateBlock(bcBlock, parent, rewards); err != nil {
386393 return errors.Sub(ErrBadBlock, err)
387394 }
388395
396+ fmt.Println("block.go _, p := range c.subProtocols")
389397 for _, p := range c.subProtocols {
390398 if err := p.ValidateBlock(block, bcBlock.TransactionStatus.GetVerifyStatus()); err != nil {
391399 return errors.Wrap(err, "sub protocol save block")
392400 }
393401 }
402+ fmt.Println("end validation")
394403
395404 if err := c.store.SaveBlock(block, bcBlock.TransactionStatus); err != nil {
396405 return err
397406 }
407+ fmt.Println("end save block")
398408
399409 c.orphanManage.Delete(&bcBlock.ID)
400410 return nil
@@ -470,16 +480,22 @@ func (c *Chain) processBlock(block *types.Block) (bool, error) {
470480 return false, err
471481 }
472482
483+ fmt.Println("saveBlock")
484+
473485 bestBlock := c.saveSubBlock(block)
474486 bestBlockHeader := &bestBlock.BlockHeader
475487
488+ fmt.Println("end save sub block")
489+
476490 c.cond.L.Lock()
477491 defer c.cond.L.Unlock()
478492 if bestBlockHeader.PreviousBlockHash == c.bestBlockHeader.Hash() {
479493 log.WithFields(log.Fields{"module": logModule}).Debug("append block to the end of mainchain")
494+ fmt.Println("go to connectBlock")
480495 return false, c.connectBlock(bestBlock)
481496 }
482497
498+ fmt.Println("doing")
483499 if bestBlockHeader.Height > c.bestBlockHeader.Height {
484500 log.WithFields(log.Fields{"module": logModule}).Debug("start to reorganize chain")
485501 return false, c.reorganizeChain(bestBlockHeader)
--- a/protocol/state/consensus_result.go
+++ b/protocol/state/consensus_result.go
@@ -2,6 +2,7 @@ package state
22
33 import (
44 "encoding/hex"
5+ "fmt"
56 "sort"
67
78 "github.com/bytom/vapor/common/arithmetic"
@@ -61,8 +62,10 @@ func CalCoinbaseReward(block *types.Block) (*CoinbaseReward, error) {
6162 } else {
6263 return nil, errors.New("not found coinbase receiver")
6364 }
65+ //fmt.Println("CalCoinbaseReward(block *types.Block) result.ControlProgram", result.ControlProgram)
6466
6567 result.Amount = consensus.BlockSubsidy(block.BlockHeader.Height)
68+ //fmt.Println("CalCoinbaseReward(block *types.Block) result.Amount", result.Amount)
6669 for _, tx := range block.Transactions {
6770 txFee, err := arithmetic.CalculateTxFee(tx)
6871 if err != nil {
@@ -71,6 +74,7 @@ func CalCoinbaseReward(block *types.Block) (*CoinbaseReward, error) {
7174
7275 result.Amount += txFee
7376 }
77+ //fmt.Println("CalCoinbaseReward(block *types.Block) result.Amount", result.Amount)
7478 return result, nil
7579 }
7680
@@ -108,6 +112,7 @@ func (c *ConsensusResult) ApplyBlock(block *types.Block) error {
108112 return err
109113 }
110114
115+ fmt.Println("ConsensusResult ApplyTransaction")
111116 for _, tx := range block.Transactions {
112117 if err := c.ApplyTransaction(tx); err != nil {
113118 return err
@@ -122,13 +127,19 @@ func (c *ConsensusResult) ApplyBlock(block *types.Block) error {
122127
123128 // ApplyTransaction calculate the consensus result for transaction
124129 func (c *ConsensusResult) ApplyTransaction(tx *types.Tx) error {
130+ fmt.Println("(c *ConsensusResult) ApplyTransaction")
131+ fmt.Println("ApplyTransaction", len(tx.Inputs))
132+ fmt.Println("ApplyTransaction", len(tx.Outputs))
125133 for _, input := range tx.Inputs {
126134 vetoInput, ok := input.TypedInput.(*types.VetoInput)
135+ fmt.Println("inputs ok:", ok)
127136 if !ok {
128137 continue
129138 }
130139
140+ fmt.Println("vetoInput", vetoInput)
131141 pubkey := hex.EncodeToString(vetoInput.Vote)
142+ fmt.Println("pubkey", pubkey)
132143 c.NumOfVote[pubkey], ok = checked.SubUint64(c.NumOfVote[pubkey], vetoInput.Amount)
133144 if !ok {
134145 return checked.ErrOverflow
@@ -141,6 +152,7 @@ func (c *ConsensusResult) ApplyTransaction(tx *types.Tx) error {
141152
142153 for _, output := range tx.Outputs {
143154 voteOutput, ok := output.TypedOutput.(*types.VoteOutput)
155+ fmt.Println("outputs ok:", ok)
144156 if !ok {
145157 continue
146158 }
@@ -156,6 +168,8 @@ func (c *ConsensusResult) ApplyTransaction(tx *types.Tx) error {
156168 // AttachCoinbaseReward attach coinbase reward
157169 func (c *ConsensusResult) AttachCoinbaseReward(block *types.Block) error {
158170 reward, err := CalCoinbaseReward(block)
171+ //fmt.Println("AttachCoinbaseReward height", block.Height)
172+ //fmt.Println("AttachCoinbaseReward reward amount, program", reward.Amount, reward.ControlProgram)
159173 if err != nil {
160174 return err
161175 }
@@ -165,8 +179,11 @@ func (c *ConsensusResult) AttachCoinbaseReward(block *types.Block) error {
165179 }
166180
167181 var ok bool
182+ //fmt.Println("reward.ControlProgram:", reward.ControlProgram)
168183 program := hex.EncodeToString(reward.ControlProgram)
184+ //fmt.Println("program:", program)
169185 c.CoinbaseReward[program], ok = checked.AddUint64(c.CoinbaseReward[program], reward.Amount)
186+ fmt.Println("AttachCoinbaseReward c.CoinbaseReward[program]", program, c.CoinbaseReward[program])
170187 if !ok {
171188 return checked.ErrOverflow
172189 }
@@ -311,6 +328,8 @@ func (c *ConsensusResult) GetCoinbaseRewards(blockHeight uint64) ([]CoinbaseRewa
311328 return rewards, nil
312329 }
313330
331+ //fmt.Println("(c *ConsensusResult) GetCoinbaseRewards", c.CoinbaseReward, "blockHeight:", blockHeight)
332+ //fmt.Println("c.CoinbaseReward ", c.CoinbaseReward)
314333 for p, amount := range c.CoinbaseReward {
315334 program, err := hex.DecodeString(p)
316335 if err != nil {
@@ -322,6 +341,7 @@ func (c *ConsensusResult) GetCoinbaseRewards(blockHeight uint64) ([]CoinbaseRewa
322341 ControlProgram: program,
323342 })
324343 }
344+ //fmt.Println("SortByAmount(rewards)")
325345 sort.Sort(SortByAmount(rewards))
326346 return rewards, nil
327347 }
--- a/protocol/state/utxo_view.go
+++ b/protocol/state/utxo_view.go
@@ -1,6 +1,8 @@
11 package state
22
33 import (
4+ "fmt"
5+
46 "github.com/bytom/vapor/consensus"
57 "github.com/bytom/vapor/database/storage"
68 "github.com/bytom/vapor/errors"
@@ -20,10 +22,12 @@ func NewUtxoViewpoint() *UtxoViewpoint {
2022 }
2123
2224 func (view *UtxoViewpoint) ApplyTransaction(block *bc.Block, tx *bc.Tx, statusFail bool) error {
25+ fmt.Println("UtxoViewpoint ApplyTransaction")
2326 if err := view.applyCrossChainUtxo(block, tx); err != nil {
2427 return err
2528 }
2629
30+ fmt.Println("view.applySpendUtxo")
2731 if err := view.applySpendUtxo(block, tx, statusFail); err != nil {
2832 return err
2933 }
@@ -38,6 +42,7 @@ func (view *UtxoViewpoint) ApplyBlock(block *bc.Block, txStatus *bc.TransactionS
3842 return err
3943 }
4044
45+ fmt.Println("UtxoViewpoint ApplyBlock", i, tx)
4146 if err := view.ApplyTransaction(block, tx, statusFail); err != nil {
4247 return err
4348 }
@@ -154,6 +159,8 @@ func (view *UtxoViewpoint) applySpendUtxo(block *bc.Block, tx *bc.Tx, statusFail
154159 continue
155160 }
156161
162+ fmt.Println("assetID:", assetID)
163+ fmt.Println("prevout", prevout)
157164 entry, ok := view.Entries[prevout]
158165 if !ok {
159166 return errors.New("fail to find utxo entry")
--- a/protocol/validation/block.go
+++ b/protocol/validation/block.go
@@ -3,6 +3,7 @@ package validation
33 import (
44 "bytes"
55 "encoding/hex"
6+ "fmt"
67 "time"
78
89 log "github.com/sirupsen/logrus"
@@ -122,11 +123,19 @@ func ValidateBlock(b *bc.Block, parent *types.BlockHeader, rewards []state.Coinb
122123 return errors.WithDetailf(errMismatchedMerkleRoot, "transaction id merkle root. compute: %v, given: %v", txMerkleRoot, *b.TransactionsRoot)
123124 }
124125
126+ fmt.Println("b.TransactionStatus.VerifyStatus", b.TransactionStatus.VerifyStatus, len(b.TransactionStatus.VerifyStatus))
127+ for i := 0; i < len(b.TransactionStatus.VerifyStatus); i++ {
128+ fmt.Println("txStatus", i, b.TransactionStatus.VerifyStatus[i])
129+ }
125130 txStatusHash, err := types.TxStatusMerkleRoot(b.TransactionStatus.VerifyStatus)
126131 if err != nil {
127132 return errors.Wrap(err, "computing transaction status merkle root")
128133 }
129134 if txStatusHash != *b.TransactionStatusHash {
135+ fmt.Println("!!! here !!")
136+ fmt.Println("txStatusHash", txStatusHash)
137+ fmt.Println("TransactionStatusHash", b.TransactionStatusHash)
138+ fmt.Println("TransactionStatusHash", *b.TransactionStatusHash)
130139 return errors.WithDetailf(errMismatchedMerkleRoot, "transaction status merkle root. compute: %v, given: %v", txStatusHash, *b.TransactionStatusHash)
131140 }
132141
--- a/protocol/validation/tx.go
+++ b/protocol/validation/tx.go
@@ -597,9 +597,11 @@ func applySoftFork001(vs *validationState, err error) {
597597 // ValidateTx validates a transaction.
598598 func ValidateTx(tx *bc.Tx, block *bc.Block) (*GasState, error) {
599599 gasStatus := &GasState{GasValid: false}
600+ fmt.Println("block.Version, tx.Version", block.Version, tx.Version)
600601 if block.Version == 1 && tx.Version != 1 {
601602 return gasStatus, errors.WithDetailf(ErrTxVersion, "block version %d, transaction version %d", block.Version, tx.Version)
602603 }
604+ fmt.Println("???")
603605 if tx.SerializedSize == 0 {
604606 return gasStatus, ErrWrongTransactionSize
605607 }
--- /dev/null
+++ b/test/rollback_test.go
@@ -0,0 +1,396 @@
1+package test
2+
3+import (
4+ "encoding/hex"
5+ "fmt"
6+ "log"
7+ "os"
8+ "testing"
9+ "time"
10+
11+ "github.com/bytom/vapor/account"
12+ "github.com/bytom/vapor/application/mov"
13+ "github.com/bytom/vapor/asset"
14+ "github.com/bytom/vapor/blockchain/pseudohsm"
15+ "github.com/bytom/vapor/config"
16+ cfg "github.com/bytom/vapor/config"
17+ "github.com/bytom/vapor/consensus"
18+ "github.com/bytom/vapor/crypto/ed25519/chainkd"
19+ "github.com/bytom/vapor/database"
20+ dbm "github.com/bytom/vapor/database/leveldb"
21+ "github.com/bytom/vapor/errors"
22+ "github.com/bytom/vapor/event"
23+ "github.com/bytom/vapor/proposal"
24+ "github.com/bytom/vapor/protocol"
25+ "github.com/bytom/vapor/protocol/bc"
26+ "github.com/bytom/vapor/protocol/bc/types"
27+ "github.com/bytom/vapor/protocol/state"
28+ "github.com/bytom/vapor/testutil"
29+ w "github.com/bytom/vapor/wallet"
30+)
31+
32+const (
33+ n = 1 // 初始化用的block数量
34+)
35+
36+var fedConsensusPath = [][]byte{
37+ []byte{0xff, 0xff, 0xff, 0xff},
38+ []byte{0xff, 0x00, 0x00, 0x00},
39+ []byte{0xff, 0xff, 0xff, 0xff},
40+ []byte{0xff, 0x00, 0x00, 0x00},
41+ []byte{0xff, 0x00, 0x00, 0x00},
42+}
43+
44+func xpub(str string) (xpub chainkd.XPub) {
45+ if err := xpub.UnmarshalText([]byte(str)); err != nil {
46+ log.Panicf("Fail converts a string to xpub")
47+ }
48+ return xpub
49+}
50+
51+func xprv(str string) (xprv chainkd.XPrv) {
52+ if err := xprv.UnmarshalText([]byte(str)); err != nil {
53+ log.Panicf("Fail converts a string to xprv")
54+ }
55+ return xprv
56+}
57+
58+var Xprvs = []chainkd.XPrv{
59+ xprv("c87f8d0f4bb4b0acbb7f69f1954c4f34d4476e114fffa7b0c853992474a9954a273c2d8f2642a7baf94ebac88f1625af9f5eaf3b13a90de27eec3de78b9fb9ca"),
60+ xprv("c80fbc34475fc9447753c00820d8448851c87f07e6bdde349260862c9bca5b4bb2e62c15e129067af869ebdf66e5829e61d6f2e47447395cc18c4166b06e8473"),
61+}
62+
63+const (
64+ warnTimeNum = 2
65+ warnTimeDenom = 5
66+ criticalTimeNum = 4
67+ criticalTimeDenom = 5
68+)
69+
70+// number 1
71+// private key: 483355b66c0e15b0913829d709b04557749b871b3bf56ad1de8fda13d3a4954aa2a56121b8eab313b8f36939e8190fe8f267f19496decb91be5644e92b669914
72+// public key: 32fe453097591f288315ef47b1ebdabf20e8bced8ede670f999980205cacddd4a2a56121b8eab313b8f36939e8190fe8f267f19496decb91be5644e92b669914
73+// derivied private key: c87f8d0f4bb4b0acbb7f69f1954c4f34d4476e114fffa7b0c853992474a9954a273c2d8f2642a7baf94ebac88f1625af9f5eaf3b13a90de27eec3de78b9fb9ca
74+// derivied public key: 4d6f710dae8094c111450ca20e054c3aed59dfcb2d29543c29901a5903755e69273c2d8f2642a7baf94ebac88f1625af9f5eaf3b13a90de27eec3de78b9fb9ca
75+
76+// number 2
77+// private key: d8e786a4eafa3456e35b2a1467d37dd84f64ba36604f8076015b76a8eec55b4b83d4fac0f94d157cfc720b77602f21b6b8a7e86f95c571e4d7986210dbce44c9
78+// public key: ebe1060254ec43bd7883e94583ff0a71ef0ec0e1ada4cd0f5ed7e9d37f1d244e83d4fac0f94d157cfc720b77602f21b6b8a7e86f95c571e4d7986210dbce44c9
79+// derivied private key: c80fbc34475fc9447753c00820d8448851c87f07e6bdde349260862c9bca5b4bb2e62c15e129067af869ebdf66e5829e61d6f2e47447395cc18c4166b06e8473
80+// derivied public key: 59184c0f1f4f13b8b256ac82df30dc12cfd66b6e09a28054933f848dc51b9a89b2e62c15e129067af869ebdf66e5829e61d6f2e47447395cc18c4166b06e8473
81+
82+func getKey() {
83+ xprv, _ := chainkd.NewXPrv(nil)
84+ fmt.Println("secretKey:", xprv)
85+
86+ xpub := xprv.XPub()
87+ fmt.Println("publicKey:", xpub)
88+
89+ derivateKey := xprv.Derive(fedConsensusPath)
90+ fmt.Println("derivateSecretKey:", derivateKey)
91+
92+ derivatePublicKey := derivateKey.XPub()
93+ fmt.Println("derivatePublicKey", derivatePublicKey)
94+}
95+
96+func newFederationConfig() *cfg.FederationConfig {
97+ return &cfg.FederationConfig{
98+ Xpubs: []chainkd.XPub{
99+ xpub("32fe453097591f288315ef47b1ebdabf20e8bced8ede670f999980205cacddd4a2a56121b8eab313b8f36939e8190fe8f267f19496decb91be5644e92b669914"),
100+ xpub("ebe1060254ec43bd7883e94583ff0a71ef0ec0e1ada4cd0f5ed7e9d37f1d244e83d4fac0f94d157cfc720b77602f21b6b8a7e86f95c571e4d7986210dbce44c9"),
101+ },
102+ Quorum: 1,
103+ }
104+}
105+
106+func getBlockerOrder(startTimestamp, blockTimestamp, numOfConsensusNode uint64) uint64 {
107+ // One round of product block time for all consensus nodes
108+ roundBlockTime := consensus.ActiveNetParams.BlockNumEachNode * numOfConsensusNode * consensus.ActiveNetParams.BlockTimeInterval
109+ // The start time of the last round of product block
110+ lastRoundStartTime := startTimestamp + (blockTimestamp-startTimestamp)/roundBlockTime*roundBlockTime
111+ // Order of blocker
112+ return (blockTimestamp - lastRoundStartTime) / (consensus.ActiveNetParams.BlockNumEachNode * consensus.ActiveNetParams.BlockTimeInterval)
113+}
114+
115+func getPrevRoundLastBlock(c *protocol.Chain, store protocol.Store, prevBlockHash *bc.Hash) (*types.BlockHeader, error) {
116+ blockHeader, err := store.GetBlockHeader(prevBlockHash)
117+ if err != nil {
118+ return nil, err
119+ }
120+
121+ for blockHeader.Height%consensus.ActiveNetParams.RoundVoteBlockNums != 0 {
122+ blockHeader, err = store.GetBlockHeader(&blockHeader.PreviousBlockHash)
123+ if err != nil {
124+ return nil, err
125+ }
126+ }
127+ return blockHeader, nil
128+}
129+
130+// according to getOrder
131+func getXprv(c *protocol.Chain, store protocol.Store, timeStamp uint64) (*chainkd.XPrv, error) {
132+ prevVoteRoundLastBlock, err := getPrevRoundLastBlock(c, store, c.BestBlockHash())
133+ if err != nil {
134+ return &(Xprvs[0]), err
135+ }
136+
137+ startTimestamp := prevVoteRoundLastBlock.Timestamp + consensus.ActiveNetParams.BlockTimeInterval
138+ order := getBlockerOrder(startTimestamp, timeStamp, uint64(len(Xprvs)))
139+ if order >= uint64(len(Xprvs)) {
140+ return nil, errors.New("bad order")
141+ }
142+ return &(Xprvs[order]), nil
143+}
144+
145+func getConsensusResult(c *protocol.Chain, store *database.Store, seq uint64, blockHeader *types.BlockHeader) (*state.ConsensusResult, error) {
146+ consensusResult, err := store.GetConsensusResult(seq)
147+ if err != nil {
148+ return nil, err
149+ }
150+
151+ return consensusResult, nil
152+}
153+
154+func TestRollback(t *testing.T) {
155+ // genesisBlock := config.GenesisBlock()
156+ testXpub, _ := hex.DecodeString("4d6f710dae8094c111450ca20e054c3aed59dfcb2d29543c29901a5903755e69273c2d8f2642a7baf94ebac88f1625af9f5eaf3b13a90de27eec3de78b9fb9ca")
157+
158+ db := dbm.NewDB("block_test_db", "leveldb", "block_test_db")
159+ defer os.RemoveAll("block_test_db")
160+
161+ cfg.CommonConfig = cfg.DefaultConfig()
162+ cfg.CommonConfig.Federation = newFederationConfig()
163+
164+ xp := xprv("c87f8d0f4bb4b0acbb7f69f1954c4f34d4476e114fffa7b0c853992474a9954a273c2d8f2642a7baf94ebac88f1625af9f5eaf3b13a90de27eec3de78b9fb9ca")
165+ cfg.CommonConfig.XPrv = &xp
166+ consensus.ActiveNetParams.RoundVoteBlockNums = 3
167+
168+ store := database.NewStore(db)
169+ dispatcher := event.NewDispatcher()
170+
171+ movCore := mov.NewMovCore(cfg.CommonConfig.DBBackend, cfg.CommonConfig.DBDir(), consensus.ActiveNetParams.MovStartHeight)
172+ txPool := protocol.NewTxPool(store, []protocol.DustFilterer{movCore}, dispatcher)
173+ chain, err := protocol.NewChain(store, txPool, []protocol.Protocoler{movCore}, dispatcher)
174+
175+ block, err := chain.GetBlockByHeight(0)
176+ if err != nil {
177+ t.Fatal(err)
178+ }
179+
180+ fmt.Println("block.Timestamp", block.Timestamp)
181+ fmt.Println(block.Transactions, len(block.Transactions))
182+ tx := block.Transactions[0]
183+ fmt.Println(tx.ID, tx.Inputs[0].ControlProgram(), tx.Outputs[0].ControlProgram())
184+
185+ hsm, err := pseudohsm.New(cfg.CommonConfig.KeysDir())
186+ walletDB := dbm.NewDB("wallet", cfg.CommonConfig.DBBackend, cfg.CommonConfig.DBDir())
187+ walletStore := database.NewWalletStore(walletDB)
188+ accountStore := database.NewAccountStore(walletDB)
189+ accounts := account.NewManager(accountStore, chain)
190+ assets := asset.NewRegistry(walletDB, chain)
191+ wallet, err := w.NewWallet(walletStore, accounts, assets, hsm, chain, dispatcher, cfg.CommonConfig.Wallet.TxIndex)
192+ if err != nil {
193+ t.Fatal("init NewWallet")
194+ }
195+
196+ // trigger rescan wallet
197+ if cfg.CommonConfig.Wallet.Rescan {
198+ wallet.RescanBlocks()
199+ }
200+
201+ cases := []struct {
202+ desc string
203+ startRunNum int
204+ runBlockNum int
205+ }{
206+ {
207+ desc: "first round block",
208+ startRunNum: 1,
209+ runBlockNum: 0,
210+ },
211+ // {
212+ // desc: "second add blocks",
213+ // startRunNum: 3,
214+ // runBlockNum: 2,
215+ // },
216+ // {
217+ // desc: "third add blocks",
218+ // startRunNum: 100,
219+ // runBlockNum: 100,
220+ // },
221+ }
222+
223+ warnDuration := time.Duration(consensus.ActiveNetParams.BlockTimeInterval*warnTimeNum/warnTimeDenom) * time.Millisecond
224+ criticalDuration := time.Duration(consensus.ActiveNetParams.BlockTimeInterval*criticalTimeNum/criticalTimeDenom) * time.Millisecond
225+
226+ s1 := &bc.Tx{ID: bc.Hash{V0: 1}}
227+ transactions := []*types.Tx{}
228+ transaction := &types.Tx{
229+ TxData: types.TxData{
230+ Inputs: []*types.TxInput{types.NewVetoInput(nil, bc.NewHash([32]byte{0xff}), *consensus.BTMAssetID, 1000000, 0, []byte{0x51}, testXpub)},
231+ Outputs: []*types.TxOutput{types.NewIntraChainOutput(*consensus.BTMAssetID, 10000000, []byte{0x51})},
232+ },
233+ Tx: s1,
234+ }
235+ transactions = append(transactions, transaction)
236+ for caseIndex, c := range cases {
237+ beforeBlocks := []*types.Block{}
238+ afterBlocks := []*types.Block{}
239+ expectConsensusResultsMap := map[uint64]*state.ConsensusResult{}
240+ nowConsensusResultsMap := map[uint64]*state.ConsensusResult{}
241+
242+ for i := 0; i < c.startRunNum; i++ {
243+ timeStamp := chain.BestBlockHeader().Timestamp + consensus.ActiveNetParams.BlockTimeInterval
244+ config.CommonConfig.XPrv, err = getXprv(chain, store, timeStamp)
245+ if err != nil {
246+ t.Fatal(err)
247+ }
248+
249+ block, err := NewBlockTemplate(chain, accounts, timeStamp, warnDuration, criticalDuration)
250+ if err != nil {
251+ t.Fatal(err)
252+ }
253+
254+ // bcBlock := types.MapBlock(block)
255+ // verifyStatus := bcBlock.TransactionStatus.VerifyStatus
256+ // fmt.Println("why", verifyStatus)
257+ // fmt.Println("rollback_test, verifyStatus", len(verifyStatus))
258+ // for index := 0; index < len(verifyStatus); index++ {
259+ // fmt.Println("verifyStatus[", index, "]", verifyStatus[index])
260+ // }
261+ // fmt.Println("i:", i, len(block.Transactions))
262+
263+ // sleep(1)
264+ // block.Transactions = append(block.Transactions, transactions...)
265+
266+ if _, err := chain.ProcessBlock(block); err != nil {
267+ t.Fatal(err)
268+ }
269+
270+ blockHash := block.Hash()
271+ gotBlock, err := store.GetBlock(&blockHash)
272+ beforeBlocks = append(beforeBlocks, gotBlock)
273+ if err != nil {
274+ t.Fatal(err)
275+ }
276+ }
277+
278+ for i := 0; i < len(beforeBlocks); i++ {
279+ block := beforeBlocks[i]
280+ blockHash := block.Hash()
281+ consensusResult, err := chain.GetConsensusResultByHash(&blockHash)
282+ if err != nil {
283+
284+ t.Fatal(err)
285+ }
286+
287+ expectConsensusResultsMap[state.CalcVoteSeq(block.Height)] = consensusResult
288+ }
289+
290+ expectChainStatus := store.GetStoreStatus()
291+ expectHeight := chain.BestBlockHeight()
292+ for i := 0; i < c.runBlockNum; i++ {
293+ timeStamp := chain.BestBlockHeader().Timestamp + consensus.ActiveNetParams.BlockTimeInterval
294+ config.CommonConfig.XPrv, err = getXprv(chain, store, timeStamp)
295+ if err != nil {
296+ t.Fatal(err)
297+ }
298+
299+ //block, err := proposal.NewBlockTemplate(chain, txPool, nil, timeStamp)
300+ block, err := proposal.NewBlockTemplate(chain, accounts, timeStamp, warnDuration, criticalDuration)
301+ //block.Transactions = transactions
302+
303+ // bcBlock := types.MapBlock(block)
304+ // verifyStatus := bcBlock.TransactionStatus.VerifyStatus
305+ // fmt.Println("rollback_test, verifyStatus", len(verifyStatus))
306+ // for index := 0; index < len(verifyStatus); index++ {
307+ // fmt.Println("verifyStatus[", index, "]", verifyStatus[index])
308+ // }
309+ // fmt.Println("i:", i, len(block.Transactions))
310+ fmt.Println(block.Transactions[0].Inputs[0].ControlProgram(), block.Transactions[0].Outputs[0].ControlProgram())
311+ if err != nil {
312+ t.Fatal(err)
313+ }
314+
315+ if _, err := chain.ProcessBlock(block); err != nil {
316+ t.Fatal(err)
317+ }
318+
319+ //fmt.Println("end process Block")
320+ blockHash := block.Hash()
321+ gotBlock, err := store.GetBlock(&blockHash)
322+ afterBlocks = append(afterBlocks, gotBlock)
323+ if err != nil {
324+ t.Fatal(err)
325+ }
326+ }
327+
328+ if err = chain.Rollback(expectHeight); err != nil {
329+ t.Fatal(err)
330+ }
331+
332+ nowHeight := chain.BestBlockHeight()
333+ if expectHeight != nowHeight {
334+ t.Fatalf("%s test failed, expected: %d, now: %d", c.desc, expectHeight, nowHeight)
335+ }
336+
337+ if !testutil.DeepEqual(store.GetStoreStatus(), expectChainStatus) {
338+ t.Errorf("got block status:%v, expect block status:%v", store.GetStoreStatus(), expectChainStatus)
339+ }
340+
341+ for i := 0; i < len(beforeBlocks); i++ {
342+ block := beforeBlocks[i]
343+ blockHash := block.Hash()
344+ gotBlock, err := store.GetBlock(&blockHash)
345+ if err != nil {
346+ t.Fatal(err)
347+ }
348+
349+ if !testutil.DeepEqual(gotBlock, block) {
350+ t.Errorf("case %v,%v: block mismatch: have %x, want %x", caseIndex, i, gotBlock, block)
351+ }
352+
353+ gotBlockHeader, err := store.GetBlockHeader(&blockHash)
354+ if err != nil {
355+ t.Fatal(err)
356+ }
357+
358+ if !testutil.DeepEqual(block.BlockHeader, *gotBlockHeader) {
359+ t.Errorf("got block header:%v, expect block header:%v", gotBlockHeader, block.BlockHeader)
360+ }
361+
362+ consensusResult, err := chain.GetConsensusResultByHash(&blockHash)
363+ if err != nil {
364+
365+ t.Fatal(err)
366+ }
367+
368+ nowConsensusResultsMap[state.CalcVoteSeq(block.Height)] = consensusResult
369+ }
370+
371+ if !testutil.DeepEqual(expectConsensusResultsMap, nowConsensusResultsMap) {
372+ t.Errorf("consensusResult is not equal!")
373+ }
374+
375+ // finalSeq := state.CalcVoteSeq(chain.BestBlockHeight())
376+ for i := 0; i < len(afterBlocks); i++ {
377+ block := afterBlocks[i]
378+ blockHash := block.Hash()
379+ _, err := store.GetBlockHeader(&blockHash)
380+ if err == nil {
381+ t.Errorf("this block should not exists!")
382+ }
383+
384+ // Code below tests will be update in later PR
385+ // this code pr is too big
386+ // to test consensusResult whether right or not
387+ // seq := state.CalcVoteSeq(block.Height)
388+ // if seq > finalSeq {
389+ // consensusResult, err := getConsensusResult(chain, store, seq, &block.BlockHeader)
390+ // if err == nil {
391+ // t.Errorf("why this result existed! %v, %v", consensusResult, err)
392+ // }
393+ // }
394+ }
395+ }
396+}
--- /dev/null
+++ b/test/rollback_util.go
@@ -0,0 +1,437 @@
1+package test
2+
3+import (
4+ "encoding/hex"
5+ "fmt"
6+ "sort"
7+ "strconv"
8+ "time"
9+
10+ log "github.com/sirupsen/logrus"
11+
12+ "github.com/bytom/vapor/account"
13+ "github.com/bytom/vapor/blockchain/txbuilder"
14+ "github.com/bytom/vapor/consensus"
15+ "github.com/bytom/vapor/errors"
16+ "github.com/bytom/vapor/protocol"
17+ "github.com/bytom/vapor/protocol/bc"
18+ "github.com/bytom/vapor/protocol/bc/types"
19+ "github.com/bytom/vapor/protocol/state"
20+ "github.com/bytom/vapor/protocol/validation"
21+ "github.com/bytom/vapor/protocol/vm/vmutil"
22+)
23+
24+const (
25+ logModule = "mining"
26+ batchApplyNum = 64
27+
28+ timeoutOk = iota + 1
29+ timeoutWarn
30+ timeoutCritical
31+)
32+
33+type byTime []*protocol.TxDesc
34+
35+func (a byTime) Len() int { return len(a) }
36+func (a byTime) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
37+func (a byTime) Less(i, j int) bool { return a[i].Added.Before(a[j].Added) }
38+
39+// NewBlockTemplate returns a new block template that is ready to be solved
40+func NewBlockTemplate(chain *protocol.Chain, accountManager *account.Manager, timestamp uint64, warnDuration, criticalDuration time.Duration) (*types.Block, error) {
41+ builder := newBlockBuilder(chain, accountManager, timestamp, warnDuration, criticalDuration)
42+ return builder.build()
43+}
44+
45+type blockBuilder struct {
46+ chain *protocol.Chain
47+ accountManager *account.Manager
48+
49+ block *types.Block
50+ txStatus *bc.TransactionStatus
51+ utxoView *state.UtxoViewpoint
52+
53+ warnTimeoutCh <-chan time.Time
54+ criticalTimeoutCh <-chan time.Time
55+ timeoutStatus uint8
56+ gasLeft int64
57+}
58+
59+func newBlockBuilder(chain *protocol.Chain, accountManager *account.Manager, timestamp uint64, warnDuration, criticalDuration time.Duration) *blockBuilder {
60+ preBlockHeader := chain.BestBlockHeader()
61+ block := &types.Block{
62+ BlockHeader: types.BlockHeader{
63+ Version: 1,
64+ Height: preBlockHeader.Height + 1,
65+ PreviousBlockHash: preBlockHeader.Hash(),
66+ Timestamp: timestamp,
67+ BlockCommitment: types.BlockCommitment{},
68+ BlockWitness: types.BlockWitness{Witness: make([][]byte, consensus.ActiveNetParams.NumOfConsensusNode)},
69+ },
70+ }
71+
72+ builder := &blockBuilder{
73+ chain: chain,
74+ accountManager: accountManager,
75+ block: block,
76+ txStatus: bc.NewTransactionStatus(),
77+ utxoView: state.NewUtxoViewpoint(),
78+ warnTimeoutCh: time.After(warnDuration),
79+ criticalTimeoutCh: time.After(criticalDuration),
80+ gasLeft: int64(consensus.ActiveNetParams.MaxBlockGas),
81+ timeoutStatus: timeoutOk,
82+ }
83+ return builder
84+}
85+
86+func (b *blockBuilder) applyCoinbaseTransaction() error {
87+ coinbaseTx, err := b.createCoinbaseTx()
88+ if err != nil {
89+ return errors.Wrap(err, "fail on create coinbase tx")
90+ }
91+
92+ gasState, err := validation.ValidateTx(coinbaseTx.Tx, &bc.Block{BlockHeader: &bc.BlockHeader{Height: b.block.Height}, Transactions: []*bc.Tx{coinbaseTx.Tx}})
93+ if err != nil {
94+ return err
95+ }
96+
97+ b.block.Transactions = append(b.block.Transactions, coinbaseTx)
98+ if err := b.txStatus.SetStatus(0, false); err != nil {
99+ return err
100+ }
101+
102+ b.gasLeft -= gasState.GasUsed
103+ return nil
104+}
105+
106+func (b *blockBuilder) applyVoteTransaction() error {
107+ tx, err := b.createVoteTx(b.accountManager, b.block.Height)
108+ if err != nil {
109+ return errors.Wrap(err, "fail on create vote tx")
110+ }
111+
112+ gasState, err := validation.ValidateTx(tx.Tx, &bc.Block{BlockHeader: &bc.BlockHeader{Height: b.block.Height}, Transactions: []*bc.Tx{tx.Tx}})
113+ if err != nil {
114+ return err
115+ }
116+
117+ b.block.Transactions = append(b.block.Transactions, tx)
118+ if err := b.txStatus.SetStatus(1, false); err != nil {
119+ return err
120+ }
121+ b.gasLeft -= gasState.GasUsed
122+
123+ return err
124+}
125+
126+func (b *blockBuilder) applyTransactions(txs []*types.Tx, timeoutStatus uint8) error {
127+ fmt.Println("test.applyTransactions")
128+ tempTxs := []*types.Tx{}
129+ for i := 0; i < len(txs); i++ {
130+ if tempTxs = append(tempTxs, txs[i]); len(tempTxs) < batchApplyNum && i != len(txs)-1 {
131+ continue
132+ }
133+
134+ fmt.Println("test", "i=", i, "preValidateTxs")
135+ results, gasLeft := preValidateTxs(tempTxs, b.chain, b.utxoView, b.gasLeft)
136+ for _, result := range results {
137+ if result.err != nil && !result.gasOnly {
138+ log.WithFields(log.Fields{"module": logModule, "error": result.err}).Error("mining block generation: skip tx due to")
139+ b.chain.GetTxPool().RemoveTransaction(&result.tx.ID)
140+ continue
141+ }
142+
143+ if err := b.txStatus.SetStatus(len(b.block.Transactions), result.gasOnly); err != nil {
144+ return err
145+ }
146+
147+ b.block.Transactions = append(b.block.Transactions, result.tx)
148+ }
149+
150+ b.gasLeft = gasLeft
151+ tempTxs = []*types.Tx{}
152+ if b.getTimeoutStatus() >= timeoutStatus {
153+ break
154+ }
155+ }
156+ return nil
157+}
158+
159+func (b *blockBuilder) applyTransactionFromPool() error {
160+ txDescList := b.chain.GetTxPool().GetTransactions()
161+ sort.Sort(byTime(txDescList))
162+
163+ poolTxs := make([]*types.Tx, len(txDescList))
164+ for i, txDesc := range txDescList {
165+ poolTxs[i] = txDesc.Tx
166+ }
167+
168+ return b.applyTransactions(poolTxs, timeoutWarn)
169+}
170+
171+func (b *blockBuilder) applyTransactionFromSubProtocol() error {
172+ cp, err := b.accountManager.GetCoinbaseControlProgram()
173+ if err != nil {
174+ return err
175+ }
176+
177+ isTimeout := func() bool {
178+ return b.getTimeoutStatus() > timeoutOk
179+ }
180+
181+ for i, p := range b.chain.SubProtocols() {
182+ if b.gasLeft <= 0 || isTimeout() {
183+ break
184+ }
185+
186+ subTxs, err := p.BeforeProposalBlock(b.block.Transactions, cp, b.block.Height, b.gasLeft, isTimeout)
187+ if err != nil {
188+ log.WithFields(log.Fields{"module": logModule, "index": i, "error": err}).Error("failed on sub protocol txs package")
189+ continue
190+ }
191+
192+ if err := b.applyTransactions(subTxs, timeoutCritical); err != nil {
193+ return err
194+ }
195+ }
196+ return nil
197+}
198+
199+func (b *blockBuilder) build() (*types.Block, error) {
200+ if err := b.applyCoinbaseTransaction(); err != nil {
201+ return nil, err
202+ }
203+
204+ if err := b.applyVoteTransaction(); err != nil {
205+ return nil, err
206+ }
207+
208+ if err := b.applyTransactionFromPool(); err != nil {
209+ return nil, err
210+ }
211+
212+ if err := b.applyTransactionFromSubProtocol(); err != nil {
213+ return nil, err
214+ }
215+
216+ if err := b.calcBlockCommitment(); err != nil {
217+ return nil, err
218+ }
219+
220+ if err := b.chain.SignBlockHeader(&b.block.BlockHeader); err != nil {
221+ return nil, err
222+ }
223+
224+ return b.block, nil
225+}
226+
227+func (b *blockBuilder) calcBlockCommitment() (err error) {
228+ var txEntries []*bc.Tx
229+ for _, tx := range b.block.Transactions {
230+ txEntries = append(txEntries, tx.Tx)
231+ }
232+
233+ b.block.BlockHeader.BlockCommitment.TransactionsMerkleRoot, err = types.TxMerkleRoot(txEntries)
234+ if err != nil {
235+ return err
236+ }
237+
238+ b.block.BlockHeader.BlockCommitment.TransactionStatusHash, err = types.TxStatusMerkleRoot(b.txStatus.VerifyStatus)
239+ for i := 0; i < len(b.txStatus.VerifyStatus); i++ {
240+ fmt.Println("txStatus", i, b.txStatus.VerifyStatus[i])
241+ }
242+ fmt.Println("b.txStatus.VerifyStatus", b.txStatus.VerifyStatus, len(b.txStatus.VerifyStatus))
243+ fmt.Println("b.block.BlockHeader.BlockCommitment.TransactionStatusHash", b.block.BlockHeader.BlockCommitment.TransactionStatusHash)
244+ return err
245+}
246+
247+// createCoinbaseTx returns a coinbase transaction paying an appropriate subsidy
248+// based on the passed block height to the provided address. When the address
249+// is nil, the coinbase transaction will instead be redeemable by anyone.
250+func (b *blockBuilder) createCoinbaseTx() (*types.Tx, error) {
251+ consensusResult, err := b.chain.GetConsensusResultByHash(&b.block.PreviousBlockHash)
252+ if err != nil {
253+ return nil, err
254+ }
255+
256+ rewards, err := consensusResult.GetCoinbaseRewards(b.block.Height - 1)
257+ if err != nil {
258+ return nil, err
259+ }
260+
261+ return createCoinbaseTxByReward(b.accountManager, b.block.Height, rewards)
262+}
263+
264+func (b *blockBuilder) createVoteTx(accountManager *account.Manager, blockHeight uint64) (*types.Tx, error) {
265+ testXpub, _ := hex.DecodeString("f3f6bcf61b65fa9d1566455a5688ca8b395efdc22e654963134b5e5cb0a45d8be522d21abc384a73177a7b9d64eba915fcfe2862d86a508a3c46dc410bdd72ad")
266+
267+ arbitrary := append([]byte{0x00}, []byte(strconv.FormatUint(blockHeight, 10))...)
268+ var script []byte
269+ var err error
270+ if accountManager == nil {
271+ script, err = vmutil.DefaultCoinbaseProgram()
272+ } else {
273+ script, err = accountManager.GetCoinbaseControlProgram()
274+ arbitrary = append(arbitrary, accountManager.GetCoinbaseArbitrary()...)
275+ }
276+ if err != nil {
277+ return nil, err
278+ }
279+
280+ if len(arbitrary) > consensus.ActiveNetParams.CoinbaseArbitrarySizeLimit {
281+ return nil, validation.ErrCoinbaseArbitraryOversize
282+ }
283+
284+ builder := txbuilder.NewBuilder(time.Now())
285+ if err = builder.AddInput(types.NewVetoInput(nil, bc.NewHash([32]byte{0xff}), *consensus.BTMAssetID, 100000000, 0, []byte{0x51}, testXpub), &txbuilder.SigningInstruction{}); err != nil {
286+ return nil, err
287+ }
288+
289+ if err = builder.AddOutput(types.NewIntraChainOutput(*consensus.BTMAssetID, 100000000, script)); err != nil {
290+ return nil, err
291+ }
292+
293+ _, txData, err := builder.Build()
294+ if err != nil {
295+ return nil, err
296+ }
297+
298+ byteData, err := txData.MarshalText()
299+ if err != nil {
300+ return nil, err
301+ }
302+
303+ txData.SerializedSize = uint64(len(byteData))
304+ tx := &types.Tx{
305+ TxData: *txData,
306+ Tx: types.MapTx(txData),
307+ }
308+ return tx, nil
309+}
310+
311+func (b *blockBuilder) getTimeoutStatus() uint8 {
312+ if b.timeoutStatus == timeoutCritical {
313+ return b.timeoutStatus
314+ }
315+
316+ select {
317+ case <-b.criticalTimeoutCh:
318+ b.timeoutStatus = timeoutCritical
319+ case <-b.warnTimeoutCh:
320+ b.timeoutStatus = timeoutWarn
321+ default:
322+ }
323+
324+ return b.timeoutStatus
325+}
326+
327+func createCoinbaseTxByReward(accountManager *account.Manager, blockHeight uint64, rewards []state.CoinbaseReward) (tx *types.Tx, err error) {
328+ arbitrary := append([]byte{0x00}, []byte(strconv.FormatUint(blockHeight, 10))...)
329+ var script []byte
330+ if accountManager == nil {
331+ script, err = vmutil.DefaultCoinbaseProgram()
332+ } else {
333+ script, err = accountManager.GetCoinbaseControlProgram()
334+ arbitrary = append(arbitrary, accountManager.GetCoinbaseArbitrary()...)
335+ }
336+ fmt.Println("blockHeight", blockHeight, "script:", script)
337+ if err != nil {
338+ return nil, err
339+ }
340+
341+ if len(arbitrary) > consensus.ActiveNetParams.CoinbaseArbitrarySizeLimit {
342+ return nil, validation.ErrCoinbaseArbitraryOversize
343+ }
344+
345+ builder := txbuilder.NewBuilder(time.Now())
346+ if err = builder.AddInput(types.NewCoinbaseInput(arbitrary), &txbuilder.SigningInstruction{}); err != nil {
347+ return nil, err
348+ }
349+
350+ if err = builder.AddOutput(types.NewIntraChainOutput(*consensus.BTMAssetID, 0, script)); err != nil {
351+ return nil, err
352+ }
353+
354+ for _, r := range rewards {
355+ if err = builder.AddOutput(types.NewIntraChainOutput(*consensus.BTMAssetID, r.Amount, r.ControlProgram)); err != nil {
356+ return nil, err
357+ }
358+ }
359+
360+ _, txData, err := builder.Build()
361+ if err != nil {
362+ return nil, err
363+ }
364+
365+ byteData, err := txData.MarshalText()
366+ if err != nil {
367+ return nil, err
368+ }
369+
370+ txData.SerializedSize = uint64(len(byteData))
371+ tx = &types.Tx{
372+ TxData: *txData,
373+ Tx: types.MapTx(txData),
374+ }
375+ return tx, nil
376+}
377+
378+type validateTxResult struct {
379+ tx *types.Tx
380+ gasOnly bool
381+ err error
382+}
383+
384+func preValidateTxs(txs []*types.Tx, chain *protocol.Chain, view *state.UtxoViewpoint, gasLeft int64) ([]*validateTxResult, int64) {
385+ var results []*validateTxResult
386+ bcBlock := &bc.Block{BlockHeader: &bc.BlockHeader{Height: chain.BestBlockHeight() + 1}}
387+ bcTxs := make([]*bc.Tx, len(txs))
388+ for i, tx := range txs {
389+ bcTxs[i] = tx.Tx
390+ }
391+
392+ validateResults := validation.ValidateTxs(bcTxs, bcBlock)
393+ for i := 0; i < len(validateResults) && gasLeft > 0; i++ {
394+ gasOnlyTx := false
395+ gasStatus := validateResults[i].GetGasState()
396+ if err := validateResults[i].GetError(); err != nil {
397+ if !gasStatus.GasValid {
398+ results = append(results, &validateTxResult{tx: txs[i], err: err})
399+ continue
400+ }
401+ gasOnlyTx = true
402+ }
403+
404+ if err := chain.GetTransactionsUtxo(view, []*bc.Tx{bcTxs[i]}); err != nil {
405+ results = append(results, &validateTxResult{tx: txs[i], err: err})
406+ continue
407+ }
408+
409+ if gasLeft-gasStatus.GasUsed < 0 {
410+ break
411+ }
412+
413+ if err := view.ApplyTransaction(bcBlock, bcTxs[i], gasOnlyTx); err != nil {
414+ results = append(results, &validateTxResult{tx: txs[i], err: err})
415+ continue
416+ }
417+
418+ if err := validateBySubProtocols(txs[i], validateResults[i].GetError() != nil, chain.SubProtocols()); err != nil {
419+ results = append(results, &validateTxResult{tx: txs[i], err: err})
420+ continue
421+ }
422+
423+ results = append(results, &validateTxResult{tx: txs[i], gasOnly: gasOnlyTx, err: validateResults[i].GetError()})
424+ gasLeft -= gasStatus.GasUsed
425+ }
426+ return results, gasLeft
427+}
428+
429+func validateBySubProtocols(tx *types.Tx, statusFail bool, subProtocols []protocol.Protocoler) error {
430+ for _, subProtocol := range subProtocols {
431+ verifyResult := &bc.TxVerifyResult{StatusFail: statusFail}
432+ if err := subProtocol.ValidateTx(tx, verifyResult); err != nil {
433+ return err
434+ }
435+ }
436+ return nil
437+}
Show on old repository browser