Golang implemented sidechain for Bytom
Revision | a33035030d41ca431cbe7df8946a8ddb0eafd559 (tree) |
---|---|
Time | 2020-02-24 11:42:56 |
Author | ipqhjjybj <250657661@qq.c...> |
Commiter | ipqhjjybj |
s
@@ -1,6 +1,7 @@ | ||
1 | 1 | package proposal |
2 | 2 | |
3 | 3 | import ( |
4 | + "fmt" | |
4 | 5 | "sort" |
5 | 6 | "strconv" |
6 | 7 | "time" |
@@ -96,12 +97,14 @@ func (b *blockBuilder) applyCoinbaseTransaction() error { | ||
96 | 97 | } |
97 | 98 | |
98 | 99 | func (b *blockBuilder) applyTransactions(txs []*types.Tx, timeoutStatus uint8) error { |
100 | + fmt.Println("applyTransactions") | |
99 | 101 | tempTxs := []*types.Tx{} |
100 | 102 | for i := 0; i < len(txs); i++ { |
101 | 103 | if tempTxs = append(tempTxs, txs[i]); len(tempTxs) < batchApplyNum && i != len(txs)-1 { |
102 | 104 | continue |
103 | 105 | } |
104 | 106 | |
107 | + fmt.Println("i=", i, "preValidateTxs") | |
105 | 108 | results, gasLeft := preValidateTxs(tempTxs, b.chain, b.utxoView, b.gasLeft) |
106 | 109 | for _, result := range results { |
107 | 110 | if result.err != nil && !result.gasOnly { |
@@ -242,11 +245,14 @@ func createCoinbaseTxByReward(accountManager *account.Manager, blockHeight uint6 | ||
242 | 245 | arbitrary := append([]byte{0x00}, []byte(strconv.FormatUint(blockHeight, 10))...) |
243 | 246 | var script []byte |
244 | 247 | if accountManager == nil { |
248 | + fmt.Println("accountManager == nil ") | |
245 | 249 | script, err = vmutil.DefaultCoinbaseProgram() |
246 | 250 | } else { |
247 | 251 | script, err = accountManager.GetCoinbaseControlProgram() |
252 | + fmt.Println("script:", script) | |
248 | 253 | arbitrary = append(arbitrary, accountManager.GetCoinbaseArbitrary()...) |
249 | 254 | } |
255 | + fmt.Println("blockHeight", blockHeight, "script:", script) | |
250 | 256 | if err != nil { |
251 | 257 | return nil, err |
252 | 258 | } |
@@ -1,6 +1,8 @@ | ||
1 | 1 | package protocol |
2 | 2 | |
3 | 3 | import ( |
4 | + "fmt" | |
5 | + | |
4 | 6 | log "github.com/sirupsen/logrus" |
5 | 7 | |
6 | 8 | "github.com/bytom/vapor/errors" |
@@ -92,10 +94,14 @@ func (c *Chain) connectBlock(block *types.Block) (err error) { | ||
92 | 94 | return err |
93 | 95 | } |
94 | 96 | |
97 | + fmt.Println("connectBlock abcd") | |
95 | 98 | utxoView := state.NewUtxoViewpoint() |
96 | 99 | if err := c.store.GetTransactionsUtxo(utxoView, bcBlock.Transactions); err != nil { |
97 | 100 | return err |
98 | 101 | } |
102 | + | |
103 | + fmt.Println("utxoView.ApplyBlock") | |
104 | + //fmt.Println("bcBlock.TransactionStatus", bcBlock.TransactionStatus) | |
99 | 105 | if err := utxoView.ApplyBlock(bcBlock, bcBlock.TransactionStatus); err != nil { |
100 | 106 | return err |
101 | 107 | } |
@@ -382,19 +388,23 @@ func (c *Chain) saveBlock(block *types.Block) error { | ||
382 | 388 | } |
383 | 389 | |
384 | 390 | bcBlock := types.MapBlock(block) |
391 | + fmt.Println("validation.ValidateBlock") | |
385 | 392 | if err := validation.ValidateBlock(bcBlock, parent, rewards); err != nil { |
386 | 393 | return errors.Sub(ErrBadBlock, err) |
387 | 394 | } |
388 | 395 | |
396 | + fmt.Println("block.go _, p := range c.subProtocols") | |
389 | 397 | for _, p := range c.subProtocols { |
390 | 398 | if err := p.ValidateBlock(block, bcBlock.TransactionStatus.GetVerifyStatus()); err != nil { |
391 | 399 | return errors.Wrap(err, "sub protocol save block") |
392 | 400 | } |
393 | 401 | } |
402 | + fmt.Println("end validation") | |
394 | 403 | |
395 | 404 | if err := c.store.SaveBlock(block, bcBlock.TransactionStatus); err != nil { |
396 | 405 | return err |
397 | 406 | } |
407 | + fmt.Println("end save block") | |
398 | 408 | |
399 | 409 | c.orphanManage.Delete(&bcBlock.ID) |
400 | 410 | return nil |
@@ -470,16 +480,22 @@ func (c *Chain) processBlock(block *types.Block) (bool, error) { | ||
470 | 480 | return false, err |
471 | 481 | } |
472 | 482 | |
483 | + fmt.Println("saveBlock") | |
484 | + | |
473 | 485 | bestBlock := c.saveSubBlock(block) |
474 | 486 | bestBlockHeader := &bestBlock.BlockHeader |
475 | 487 | |
488 | + fmt.Println("end save sub block") | |
489 | + | |
476 | 490 | c.cond.L.Lock() |
477 | 491 | defer c.cond.L.Unlock() |
478 | 492 | if bestBlockHeader.PreviousBlockHash == c.bestBlockHeader.Hash() { |
479 | 493 | log.WithFields(log.Fields{"module": logModule}).Debug("append block to the end of mainchain") |
494 | + fmt.Println("go to connectBlock") | |
480 | 495 | return false, c.connectBlock(bestBlock) |
481 | 496 | } |
482 | 497 | |
498 | + fmt.Println("doing") | |
483 | 499 | if bestBlockHeader.Height > c.bestBlockHeader.Height { |
484 | 500 | log.WithFields(log.Fields{"module": logModule}).Debug("start to reorganize chain") |
485 | 501 | return false, c.reorganizeChain(bestBlockHeader) |
@@ -2,6 +2,7 @@ package state | ||
2 | 2 | |
3 | 3 | import ( |
4 | 4 | "encoding/hex" |
5 | + "fmt" | |
5 | 6 | "sort" |
6 | 7 | |
7 | 8 | "github.com/bytom/vapor/common/arithmetic" |
@@ -61,8 +62,10 @@ func CalCoinbaseReward(block *types.Block) (*CoinbaseReward, error) { | ||
61 | 62 | } else { |
62 | 63 | return nil, errors.New("not found coinbase receiver") |
63 | 64 | } |
65 | + //fmt.Println("CalCoinbaseReward(block *types.Block) result.ControlProgram", result.ControlProgram) | |
64 | 66 | |
65 | 67 | result.Amount = consensus.BlockSubsidy(block.BlockHeader.Height) |
68 | + //fmt.Println("CalCoinbaseReward(block *types.Block) result.Amount", result.Amount) | |
66 | 69 | for _, tx := range block.Transactions { |
67 | 70 | txFee, err := arithmetic.CalculateTxFee(tx) |
68 | 71 | if err != nil { |
@@ -71,6 +74,7 @@ func CalCoinbaseReward(block *types.Block) (*CoinbaseReward, error) { | ||
71 | 74 | |
72 | 75 | result.Amount += txFee |
73 | 76 | } |
77 | + //fmt.Println("CalCoinbaseReward(block *types.Block) result.Amount", result.Amount) | |
74 | 78 | return result, nil |
75 | 79 | } |
76 | 80 |
@@ -108,6 +112,7 @@ func (c *ConsensusResult) ApplyBlock(block *types.Block) error { | ||
108 | 112 | return err |
109 | 113 | } |
110 | 114 | |
115 | + fmt.Println("ConsensusResult ApplyTransaction") | |
111 | 116 | for _, tx := range block.Transactions { |
112 | 117 | if err := c.ApplyTransaction(tx); err != nil { |
113 | 118 | return err |
@@ -122,13 +127,19 @@ func (c *ConsensusResult) ApplyBlock(block *types.Block) error { | ||
122 | 127 | |
123 | 128 | // ApplyTransaction calculate the consensus result for transaction |
124 | 129 | 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)) | |
125 | 133 | for _, input := range tx.Inputs { |
126 | 134 | vetoInput, ok := input.TypedInput.(*types.VetoInput) |
135 | + fmt.Println("inputs ok:", ok) | |
127 | 136 | if !ok { |
128 | 137 | continue |
129 | 138 | } |
130 | 139 | |
140 | + fmt.Println("vetoInput", vetoInput) | |
131 | 141 | pubkey := hex.EncodeToString(vetoInput.Vote) |
142 | + fmt.Println("pubkey", pubkey) | |
132 | 143 | c.NumOfVote[pubkey], ok = checked.SubUint64(c.NumOfVote[pubkey], vetoInput.Amount) |
133 | 144 | if !ok { |
134 | 145 | return checked.ErrOverflow |
@@ -141,6 +152,7 @@ func (c *ConsensusResult) ApplyTransaction(tx *types.Tx) error { | ||
141 | 152 | |
142 | 153 | for _, output := range tx.Outputs { |
143 | 154 | voteOutput, ok := output.TypedOutput.(*types.VoteOutput) |
155 | + fmt.Println("outputs ok:", ok) | |
144 | 156 | if !ok { |
145 | 157 | continue |
146 | 158 | } |
@@ -156,6 +168,8 @@ func (c *ConsensusResult) ApplyTransaction(tx *types.Tx) error { | ||
156 | 168 | // AttachCoinbaseReward attach coinbase reward |
157 | 169 | func (c *ConsensusResult) AttachCoinbaseReward(block *types.Block) error { |
158 | 170 | reward, err := CalCoinbaseReward(block) |
171 | + //fmt.Println("AttachCoinbaseReward height", block.Height) | |
172 | + //fmt.Println("AttachCoinbaseReward reward amount, program", reward.Amount, reward.ControlProgram) | |
159 | 173 | if err != nil { |
160 | 174 | return err |
161 | 175 | } |
@@ -165,8 +179,11 @@ func (c *ConsensusResult) AttachCoinbaseReward(block *types.Block) error { | ||
165 | 179 | } |
166 | 180 | |
167 | 181 | var ok bool |
182 | + //fmt.Println("reward.ControlProgram:", reward.ControlProgram) | |
168 | 183 | program := hex.EncodeToString(reward.ControlProgram) |
184 | + //fmt.Println("program:", program) | |
169 | 185 | c.CoinbaseReward[program], ok = checked.AddUint64(c.CoinbaseReward[program], reward.Amount) |
186 | + fmt.Println("AttachCoinbaseReward c.CoinbaseReward[program]", program, c.CoinbaseReward[program]) | |
170 | 187 | if !ok { |
171 | 188 | return checked.ErrOverflow |
172 | 189 | } |
@@ -311,6 +328,8 @@ func (c *ConsensusResult) GetCoinbaseRewards(blockHeight uint64) ([]CoinbaseRewa | ||
311 | 328 | return rewards, nil |
312 | 329 | } |
313 | 330 | |
331 | + //fmt.Println("(c *ConsensusResult) GetCoinbaseRewards", c.CoinbaseReward, "blockHeight:", blockHeight) | |
332 | + //fmt.Println("c.CoinbaseReward ", c.CoinbaseReward) | |
314 | 333 | for p, amount := range c.CoinbaseReward { |
315 | 334 | program, err := hex.DecodeString(p) |
316 | 335 | if err != nil { |
@@ -322,6 +341,7 @@ func (c *ConsensusResult) GetCoinbaseRewards(blockHeight uint64) ([]CoinbaseRewa | ||
322 | 341 | ControlProgram: program, |
323 | 342 | }) |
324 | 343 | } |
344 | + //fmt.Println("SortByAmount(rewards)") | |
325 | 345 | sort.Sort(SortByAmount(rewards)) |
326 | 346 | return rewards, nil |
327 | 347 | } |
@@ -1,6 +1,8 @@ | ||
1 | 1 | package state |
2 | 2 | |
3 | 3 | import ( |
4 | + "fmt" | |
5 | + | |
4 | 6 | "github.com/bytom/vapor/consensus" |
5 | 7 | "github.com/bytom/vapor/database/storage" |
6 | 8 | "github.com/bytom/vapor/errors" |
@@ -20,10 +22,12 @@ func NewUtxoViewpoint() *UtxoViewpoint { | ||
20 | 22 | } |
21 | 23 | |
22 | 24 | func (view *UtxoViewpoint) ApplyTransaction(block *bc.Block, tx *bc.Tx, statusFail bool) error { |
25 | + fmt.Println("UtxoViewpoint ApplyTransaction") | |
23 | 26 | if err := view.applyCrossChainUtxo(block, tx); err != nil { |
24 | 27 | return err |
25 | 28 | } |
26 | 29 | |
30 | + fmt.Println("view.applySpendUtxo") | |
27 | 31 | if err := view.applySpendUtxo(block, tx, statusFail); err != nil { |
28 | 32 | return err |
29 | 33 | } |
@@ -38,6 +42,7 @@ func (view *UtxoViewpoint) ApplyBlock(block *bc.Block, txStatus *bc.TransactionS | ||
38 | 42 | return err |
39 | 43 | } |
40 | 44 | |
45 | + fmt.Println("UtxoViewpoint ApplyBlock", i, tx) | |
41 | 46 | if err := view.ApplyTransaction(block, tx, statusFail); err != nil { |
42 | 47 | return err |
43 | 48 | } |
@@ -154,6 +159,8 @@ func (view *UtxoViewpoint) applySpendUtxo(block *bc.Block, tx *bc.Tx, statusFail | ||
154 | 159 | continue |
155 | 160 | } |
156 | 161 | |
162 | + fmt.Println("assetID:", assetID) | |
163 | + fmt.Println("prevout", prevout) | |
157 | 164 | entry, ok := view.Entries[prevout] |
158 | 165 | if !ok { |
159 | 166 | return errors.New("fail to find utxo entry") |
@@ -3,6 +3,7 @@ package validation | ||
3 | 3 | import ( |
4 | 4 | "bytes" |
5 | 5 | "encoding/hex" |
6 | + "fmt" | |
6 | 7 | "time" |
7 | 8 | |
8 | 9 | log "github.com/sirupsen/logrus" |
@@ -122,11 +123,19 @@ func ValidateBlock(b *bc.Block, parent *types.BlockHeader, rewards []state.Coinb | ||
122 | 123 | return errors.WithDetailf(errMismatchedMerkleRoot, "transaction id merkle root. compute: %v, given: %v", txMerkleRoot, *b.TransactionsRoot) |
123 | 124 | } |
124 | 125 | |
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 | + } | |
125 | 130 | txStatusHash, err := types.TxStatusMerkleRoot(b.TransactionStatus.VerifyStatus) |
126 | 131 | if err != nil { |
127 | 132 | return errors.Wrap(err, "computing transaction status merkle root") |
128 | 133 | } |
129 | 134 | 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) | |
130 | 139 | return errors.WithDetailf(errMismatchedMerkleRoot, "transaction status merkle root. compute: %v, given: %v", txStatusHash, *b.TransactionStatusHash) |
131 | 140 | } |
132 | 141 |
@@ -597,9 +597,11 @@ func applySoftFork001(vs *validationState, err error) { | ||
597 | 597 | // ValidateTx validates a transaction. |
598 | 598 | func ValidateTx(tx *bc.Tx, block *bc.Block) (*GasState, error) { |
599 | 599 | gasStatus := &GasState{GasValid: false} |
600 | + fmt.Println("block.Version, tx.Version", block.Version, tx.Version) | |
600 | 601 | if block.Version == 1 && tx.Version != 1 { |
601 | 602 | return gasStatus, errors.WithDetailf(ErrTxVersion, "block version %d, transaction version %d", block.Version, tx.Version) |
602 | 603 | } |
604 | + fmt.Println("???") | |
603 | 605 | if tx.SerializedSize == 0 { |
604 | 606 | return gasStatus, ErrWrongTransactionSize |
605 | 607 | } |
@@ -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 | +} |
@@ -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 | +} |