"testing"
"time"
+ dbm "github.com/bytom/bytom/database/leveldb"
"github.com/bytom/bytom/protocol/bc"
"github.com/bytom/bytom/testutil"
- dbm "github.com/bytom/bytom/database/leveldb"
)
func TestAddUnconfirmedUtxo(t *testing.T) {
func (a *voteOutputAction) ActionType() string {
return "vote_output"
}
-
batch.Set(calcCheckpointKey(checkpoint.Height, &checkpoint.Hash), data)
log.WithFields(log.Fields{
- "module": logModule,
- "height": checkpoint.Height,
- "hash": checkpoint.Hash.String(),
- "status": checkpoint.Status,
+ "module": logModule,
+ "height": checkpoint.Height,
+ "hash": checkpoint.Hash.String(),
+ "status": checkpoint.Status,
"duration": time.Since(startTime),
}).Info("checkpoint saved on disk")
}
}
contractView := state.NewContractViewpoint()
- if err := store.SaveChainStatus(node, view, contractView,0, &bc.Hash{}); err != nil {
+ if err := store.SaveChainStatus(node, view, contractView, 0, &bc.Hash{}); err != nil {
t.Fatal(err)
}
t.Errorf("got block header:%v, expect block header:%v", gotBlockHeader, block.BlockHeader)
}
}
-
"testing"
"time"
- "github.com/bytom/bytom/testcontrol"
"github.com/bytom/bytom/consensus"
dbm "github.com/bytom/bytom/database/leveldb"
"github.com/bytom/bytom/errors"
"github.com/bytom/bytom/protocol/bc"
"github.com/bytom/bytom/protocol/bc/types"
"github.com/bytom/bytom/test/mock"
+ "github.com/bytom/bytom/testcontrol"
"github.com/bytom/bytom/testutil"
)
}
}
-func (p *Peer) getRelatedTxs(txs []*types.Tx) ([]*types.Tx) {
+func (p *Peer) getRelatedTxs(txs []*types.Tx) []*types.Tx {
var relatedTxs []*types.Tx
for _, tx := range txs {
if p.isRelatedTx(tx) {
package proposal
import (
+ "encoding/hex"
"sort"
"strconv"
"time"
func (b *blockBuilder) build() (*types.Block, error) {
b.block.Transactions = []*types.Tx{nil}
- feeAmount, err := b.applyTransactionFromPool()
- if err != nil {
+ if err := b.applyTransactionFromPool(); err != nil {
return nil, err
}
- if err := b.applyCoinbaseTransaction(feeAmount); err != nil {
+ if err := b.applyCoinbaseTransaction(); err != nil {
return nil, err
}
return b.block, nil
}
-func (b *blockBuilder) applyCoinbaseTransaction(feeAmount uint64) error {
- coinbaseTx, err := b.createCoinbaseTx(feeAmount)
+func (b *blockBuilder) applyCoinbaseTransaction() error {
+ coinbaseTx, err := b.createCoinbaseTx()
if err != nil {
return errors.Wrap(err, "fail on create coinbase tx")
}
return nil
}
-func (b *blockBuilder) applyTransactionFromPool() (uint64, error) {
+func (b *blockBuilder) applyTransactionFromPool() error {
txDescList := b.chain.GetTxPool().GetTransactions()
sort.Sort(byTime(txDescList))
return b.applyTransactions(txDescList, timeoutWarn)
// createCoinbaseTx returns a coinbase transaction paying an appropriate subsidy
// based on the passed block height to the provided address. When the address
// is nil, the coinbase transaction will instead be redeemable by anyone.
-func (b *blockBuilder) createCoinbaseTx(feeAmount uint64) (tx *types.Tx, err error) {
+func (b *blockBuilder) createCoinbaseTx() (tx *types.Tx, err error) {
arbitrary := append([]byte{0x00}, []byte(strconv.FormatUint(b.block.Height, 10))...)
var script []byte
if b.accountManager == nil {
return nil, err
}
- coinbaseAmount := consensus.BlockSubsidy(b.block.Height)
- if err = builder.AddOutput(types.NewOriginalTxOutput(*consensus.BTMAssetID, coinbaseAmount + feeAmount, script, [][]byte{})); err != nil {
+ checkpoint, err := b.getPrevCheckpoint()
+ if err != nil {
return nil, err
}
- //TODO: calculate reward to proposer
+
+ if b.block.Height%state.BlocksOfEpoch == 1 && b.block.Height != 1 {
+ for controlProgram, amount := range checkpoint.Rewards {
+ controlProgramBytes, err := hex.DecodeString(controlProgram)
+ if err != nil {
+ return nil, err
+ }
+
+ if err := builder.AddOutput(types.NewOriginalTxOutput(*consensus.BTMAssetID, amount, controlProgramBytes, [][]byte{})); err != nil {
+ return nil, err
+ }
+ }
+ } else {
+ if err = builder.AddOutput(types.NewOriginalTxOutput(*consensus.BTMAssetID, 0, script, [][]byte{})); err != nil {
+ return nil, err
+ }
+ }
_, txData, err := builder.Build()
if err != nil {
return tx, nil
}
-func (b *blockBuilder) applyTransactions(txs []*protocol.TxDesc, timeoutStatus uint8) (uint64, error) {
- var feeAmount uint64
+func (b *blockBuilder) applyTransactions(txs []*protocol.TxDesc, timeoutStatus uint8) error {
batchTxs := []*protocol.TxDesc{}
for i := 0; i < len(txs); i++ {
if batchTxs = append(batchTxs, txs[i]); len(batchTxs) < batchApplyNum && i != len(txs)-1 {
}
results, gasLeft := b.preValidateTxs(batchTxs, b.chain, b.utxoView, b.gasLeft)
- for j, result := range results {
+ for _, result := range results {
if result.err != nil {
log.WithFields(log.Fields{"module": logModule, "error": result.err}).Error("propose block generation: skip tx due to")
b.chain.GetTxPool().RemoveTransaction(&result.tx.ID)
}
b.block.Transactions = append(b.block.Transactions, result.tx)
- feeAmount += batchTxs[j].Fee
}
b.gasLeft = gasLeft
break
}
}
- return feeAmount, nil
+ return nil
}
type validateTxResult struct {
return b.timeoutStatus
}
+
+func (b *blockBuilder) prevBlockHash() *bc.Hash {
+ return &b.block.PreviousBlockHash
+}
+
+func (b *blockBuilder) getPrevCheckpoint() (*state.Checkpoint, error) {
+ return b.chain.PrevCheckpointByPrevHash(b.prevBlockHash())
+}
ParentHash: parent.Hash,
Parent: parent,
Status: state.Growing,
+ Rewards: make(map[string]uint64),
Votes: make(map[string]uint64),
Guaranties: make(map[string]uint64),
}
node.addChild(&treeNode{checkpoint: checkpoint})
} else if mod == 0 {
checkpoint.Status = state.Unjustified
+ if err := checkpoint.ApplyFederationReward(); err != nil {
+ return nil, err
+ }
+ }
+
+ if err := checkpoint.ApplyValidatorReward(block); err != nil {
+ return nil, err
}
checkpoint.Height = block.Height
return node, nil
}
-func applyTransactions(target *state.Checkpoint, transactions []*types.Tx) error {for _, tx := range transactions {
+func applyTransactions(target *state.Checkpoint, transactions []*types.Tx) error {
+ for _, tx := range transactions {
for _, input := range tx.Inputs {
if vetoInput, ok := input.TypedInput.(*types.VetoInput); ok {
if err := processVeto(vetoInput, target); err != nil {
package types
import (
+ "github.com/bytom/bytom/consensus"
"github.com/bytom/bytom/protocol/bc"
"github.com/bytom/bytom/protocol/vm"
"github.com/bytom/bytom/protocol/vm/vmutil"
func (mh *mapHelper) mapCoinbaseInput(i int, input *CoinbaseInput) {
mh.coinbase = bc.NewCoinbase(input.Arbitrary)
mh.inputIDs[i] = mh.addEntry(mh.coinbase)
+ var totalAmount uint64
+ for _, output := range mh.txData.Outputs {
+ totalAmount += output.Amount
+ }
mh.muxSources[i] = &bc.ValueSource{
Ref: &mh.inputIDs[i],
- Value: &mh.txData.Outputs[0].AssetAmount,
+ Value: &bc.AssetAmount{AssetId: consensus.BTMAssetID, Amount: totalAmount},
}
}
"737461746544617461", // output 0: state data
"00", // output 1: witness length
}, ""),
- hash: testutil.MustDecodeHash("9f0ca64c282b7069c67af78e989a14ed8d208aa99222370d941dad4bbf69cb2c"),
+ hash: testutil.MustDecodeHash("27d7fae74355ee9de2014bc51c30de27afa922ac4171eca1f38a05965c899c79"),
},
}
for i, test := range cases {
bcBlock := types.MapBlock(block)
parent := c.index.GetNode(&block.PreviousBlockHash)
- if err := validation.ValidateBlock(bcBlock, parent, c.ProgramConverter); err != nil {
+ checkpoint, err := c.PrevCheckpointByPrevHash(&block.PreviousBlockHash)
+ if err != nil {
+ return err
+ }
+
+ if err := validation.ValidateBlock(bcBlock, parent, checkpoint, c.ProgramConverter); err != nil {
return errors.Sub(ErrBadBlock, err)
}
func (c *Chain) GetTxPool() *TxPool {
return c.txPool
}
+
+// PrevCheckpointByPrevHash get previous checkpoint by previous block hash
+func (c *Chain) PrevCheckpointByPrevHash(preBlockHash *bc.Hash) (*state.Checkpoint, error) {
+ return c.casper.parentCheckpointByPrevHash(preBlockHash)
+}
Status CheckpointStatus
Rewards map[string]uint64 // controlProgram -> num of reward
- Votes map[string]uint64 // putKey -> num of vote
+ Votes map[string]uint64 // pubKey -> num of vote
Guaranties map[string]uint64 // pubKey -> num of guaranty
}
const (
totalSupply = 15.66 * 1e16
- singleBlockReward = uint64(570776255) //AnnualSupply(0.3 * 1e16) / AnnualBlock(365 * 24 * 60 * 10)
+ singleBlockReward = uint64(570776255) // AnnualSupply(0.3 * 1e16) / AnnualBlock(365 * 24 * 60 * 10)
rewardThreshold = 0.5
)
}
}
+ if c.Parent == nil {
+ return errors.New("the checkpoint parent is nil")
+ }
+
validatorReward, err := validatorRewardPerBlock(c.Parent)
if err != nil {
return err
// ApplyFederationReward federation gain the reward in an epoch
func (c *Checkpoint) ApplyFederationReward() error {
+ if c.Parent == nil {
+ return errors.New("the checkpoint parent is nil")
+ }
+
federationReward, err := federationBlockReward(c.Parent)
if err != nil {
return err
func (s *mockStore) GetBlockHeader(hash *bc.Hash) (*types.BlockHeader, error) { return nil, nil }
func (s *mockStore) GetCheckpoint(hash *bc.Hash) (*state.Checkpoint, error) { return nil, nil }
func (s *mockStore) GetCheckpointsByHeight(u uint64) ([]*state.Checkpoint, error) { return nil, nil }
-func (s *mockStore) SaveCheckpoints([]*state.Checkpoint) error { return nil }
-func (s *mockStore) CheckpointsFromNode(height uint64, hash *bc.Hash) ([]*state.Checkpoint, error) { return nil, nil }
-func (s *mockStore) BlockExist(hash *bc.Hash) bool { return false }
-func (s *mockStore) GetBlock(*bc.Hash) (*types.Block, error) { return nil, nil }
-func (s *mockStore) GetStoreStatus() *BlockStoreState { return nil }
-func (s *mockStore) GetTransactionsUtxo(*state.UtxoViewpoint, []*bc.Tx) error { return nil }
-func (s *mockStore) GetUtxo(*bc.Hash) (*storage.UtxoEntry, error) { return nil, nil }
-func (s *mockStore) GetContract(hash [32]byte) ([]byte, error) { return nil, nil }
-func (s *mockStore) LoadBlockIndex(uint64) (*state.BlockIndex, error) { return nil, nil }
-func (s *mockStore) SaveBlock(*types.Block) error { return nil }
-func (s *mockStore) SaveBlockHeader(*types.BlockHeader) error { return nil }
+func (s *mockStore) SaveCheckpoints([]*state.Checkpoint) error { return nil }
+func (s *mockStore) CheckpointsFromNode(height uint64, hash *bc.Hash) ([]*state.Checkpoint, error) {
+ return nil, nil
+}
+func (s *mockStore) BlockExist(hash *bc.Hash) bool { return false }
+func (s *mockStore) GetBlock(*bc.Hash) (*types.Block, error) { return nil, nil }
+func (s *mockStore) GetStoreStatus() *BlockStoreState { return nil }
+func (s *mockStore) GetTransactionsUtxo(*state.UtxoViewpoint, []*bc.Tx) error { return nil }
+func (s *mockStore) GetUtxo(*bc.Hash) (*storage.UtxoEntry, error) { return nil, nil }
+func (s *mockStore) GetContract(hash [32]byte) ([]byte, error) { return nil, nil }
+func (s *mockStore) LoadBlockIndex(uint64) (*state.BlockIndex, error) { return nil, nil }
+func (s *mockStore) SaveBlock(*types.Block) error { return nil }
+func (s *mockStore) SaveBlockHeader(*types.BlockHeader) error { return nil }
func (s *mockStore) SaveChainStatus(*state.BlockNode, *state.UtxoViewpoint, *state.ContractViewpoint, uint64, *bc.Hash) error {
return nil
}
func (s *mockStore1) GetBlockHeader(hash *bc.Hash) (*types.BlockHeader, error) { return nil, nil }
func (s *mockStore1) GetCheckpoint(hash *bc.Hash) (*state.Checkpoint, error) { return nil, nil }
func (s *mockStore1) GetCheckpointsByHeight(u uint64) ([]*state.Checkpoint, error) { return nil, nil }
-func (s *mockStore1) SaveCheckpoints([]*state.Checkpoint) error { return nil }
-func (s *mockStore1) CheckpointsFromNode(height uint64, hash *bc.Hash) ([]*state.Checkpoint, error) { return nil, nil }
+func (s *mockStore1) SaveCheckpoints([]*state.Checkpoint) error { return nil }
+func (s *mockStore1) CheckpointsFromNode(height uint64, hash *bc.Hash) ([]*state.Checkpoint, error) {
+ return nil, nil
+}
func (s *mockStore1) BlockExist(hash *bc.Hash) bool { return false }
func (s *mockStore1) GetBlock(*bc.Hash) (*types.Block, error) { return nil, nil }
func (s *mockStore1) GetStoreStatus() *BlockStoreState { return nil }
}
return nil
}
-func (s *mockStore1) GetUtxo(*bc.Hash) (*storage.UtxoEntry, error) { return nil, nil }
-func (s *mockStore1) GetContract(hash [32]byte) ([]byte, error) { return nil, nil }
-func (s *mockStore1) LoadBlockIndex(uint64) (*state.BlockIndex, error) { return nil, nil }
-func (s *mockStore1) SaveBlock(*types.Block) error { return nil }
-func (s *mockStore1) SaveBlockHeader(*types.BlockHeader) error { return nil }
-func (s *mockStore1) SaveChainStatus(*state.BlockNode, *state.UtxoViewpoint, *state.ContractViewpoint, uint64, *bc.Hash) error { return nil}
+func (s *mockStore1) GetUtxo(*bc.Hash) (*storage.UtxoEntry, error) { return nil, nil }
+func (s *mockStore1) GetContract(hash [32]byte) ([]byte, error) { return nil, nil }
+func (s *mockStore1) LoadBlockIndex(uint64) (*state.BlockIndex, error) { return nil, nil }
+func (s *mockStore1) SaveBlock(*types.Block) error { return nil }
+func (s *mockStore1) SaveBlockHeader(*types.BlockHeader) error { return nil }
+func (s *mockStore1) SaveChainStatus(*state.BlockNode, *state.UtxoViewpoint, *state.ContractViewpoint, uint64, *bc.Hash) error {
+ return nil
+}
func TestProcessTransaction(t *testing.T) {
txPool := &TxPool{
package validation
import (
+ "encoding/hex"
"time"
log "github.com/sirupsen/logrus"
return nil
}
-func checkCoinbaseAmount(b *bc.Block, amount uint64) error {
+func checkCoinbaseAmount(b *bc.Block, checkpoint *state.Checkpoint) error {
if len(b.Transactions) == 0 {
return errors.Wrap(ErrWrongCoinbaseTransaction, "block is empty")
}
tx := b.Transactions[0]
- if len(tx.TxHeader.ResultIds) != 1 {
- return errors.Wrap(ErrWrongCoinbaseTransaction, "have more than 1 output")
+ if len(tx.TxHeader.ResultIds) == 0 {
+ return errors.Wrap(ErrWrongCoinbaseTransaction, "tx header resultIds is empty")
}
- output, err := tx.Output(*tx.TxHeader.ResultIds[0])
- if err != nil {
- return err
- }
+ if b.Height%state.BlocksOfEpoch != 1 || b.Height == 1 {
+ output, err := tx.Output(*tx.TxHeader.ResultIds[0])
+ if err != nil {
+ return err
+ }
+
+ if output.Source.Value.Amount != 0 {
+ return errors.Wrap(ErrWrongCoinbaseTransaction, "dismatch output amount")
+ }
- if output.Source.Value.Amount != amount {
- return errors.Wrap(ErrWrongCoinbaseTransaction, "dismatch output amount")
+ if len(tx.TxHeader.ResultIds) != 1 {
+ return errors.Wrap(ErrWrongCoinbaseTransaction, "have more than 1 output")
+ }
+ } else {
+ if len(tx.TxHeader.ResultIds) != len(checkpoint.Rewards) {
+ return errors.Wrap(ErrWrongCoinbaseTransaction)
+ }
+
+ rewards := checkpoint.Rewards
+ for i := 0; i < len(tx.TxHeader.ResultIds); i++ {
+ output := tx.TxHeader.ResultIds[i]
+ out, err := tx.Output(*output)
+ if err != nil {
+ return err
+ }
+
+ if rewards[hex.EncodeToString(out.ControlProgram.Code)] != out.Source.Value.Amount {
+ return errors.Wrap(ErrWrongCoinbaseTransaction)
+ }
+ }
}
+
return nil
}
}
// ValidateBlock validates a block and the transactions within.
-func ValidateBlock(b *bc.Block, parent *state.BlockNode, converter ProgramConverterFunc) error {
+func ValidateBlock(b *bc.Block, parent *state.BlockNode, checkpoint *state.Checkpoint, converter ProgramConverterFunc) error {
startTime := time.Now()
if err := ValidateBlockHeader(b, parent); err != nil {
return err
}
blockGasSum := uint64(0)
- coinbaseAmount := consensus.BlockSubsidy(b.BlockHeader.Height)
+
validateResults := ValidateTxs(b.Transactions, b, converter)
for i, validateResult := range validateResults {
if validateResult.err != nil {
return errors.Wrapf(validateResult.err, "validate of transaction %d of %d", i, len(b.Transactions))
}
- coinbaseAmount += validateResult.gasStatus.BTMValue
if blockGasSum += uint64(validateResult.gasStatus.GasUsed); blockGasSum > consensus.MaxBlockGas {
return errOverBlockLimit
}
}
- if err := checkCoinbaseAmount(b, coinbaseAmount); err != nil {
+ if err := checkCoinbaseAmount(b, checkpoint); err != nil {
return err
}
package validation
import (
+ "encoding/hex"
"math"
"testing"
"time"
func TestCheckCoinbaseAmount(t *testing.T) {
cases := []struct {
- txs []*types.Tx
- amount uint64
- err error
+ block *types.Block
+ checkpoint *state.Checkpoint
+ err error
}{
{
- txs: []*types.Tx{
- types.NewTx(types.TxData{
- Inputs: []*types.TxInput{types.NewCoinbaseInput(nil)},
- Outputs: []*types.TxOutput{types.NewOriginalTxOutput(*consensus.BTMAssetID, 5000, nil, nil)},
- }),
+ block: &types.Block{
+ BlockHeader: types.BlockHeader{Height: 0},
+ Transactions: []*types.Tx{
+ types.NewTx(types.TxData{
+ Inputs: []*types.TxInput{types.NewCoinbaseInput(nil)},
+ Outputs: []*types.TxOutput{
+ types.NewOriginalTxOutput(*consensus.BTMAssetID, 0, []byte("controlProgram"), nil),
+ },
+ }),
+ },
},
- amount: 5000,
- err: nil,
+ checkpoint: &state.Checkpoint{
+ Rewards: map[string]uint64{hex.EncodeToString([]byte("controlProgram")): 5000},
+ },
+ err: nil,
},
{
- txs: []*types.Tx{
- types.NewTx(types.TxData{
- Inputs: []*types.TxInput{types.NewCoinbaseInput(nil)},
- Outputs: []*types.TxOutput{types.NewOriginalTxOutput(*consensus.BTMAssetID, 5000, nil, nil)},
- }),
+ block: &types.Block{
+ BlockHeader: types.BlockHeader{Height: state.BlocksOfEpoch + 1},
+ Transactions: []*types.Tx{
+ types.NewTx(types.TxData{
+ Inputs: []*types.TxInput{types.NewCoinbaseInput(nil)},
+ Outputs: []*types.TxOutput{
+ types.NewOriginalTxOutput(*consensus.BTMAssetID, 5000, []byte("controlProgram"), nil),
+ },
+ }),
+ },
},
- amount: 6000,
- err: ErrWrongCoinbaseTransaction,
+ checkpoint: &state.Checkpoint{
+ Rewards: map[string]uint64{hex.EncodeToString([]byte("controlProgram")): 5000},
+ },
+ err: nil,
},
{
- txs: []*types.Tx{},
- amount: 5000,
- err: ErrWrongCoinbaseTransaction,
+ block: &types.Block{
+ BlockHeader: types.BlockHeader{Height: state.BlocksOfEpoch + 1},
+ Transactions: []*types.Tx{
+ types.NewTx(types.TxData{
+ Inputs: []*types.TxInput{types.NewCoinbaseInput(nil)},
+ Outputs: []*types.TxOutput{
+ types.NewOriginalTxOutput(*consensus.BTMAssetID, 5000, []byte("controlProgram1"), nil),
+ types.NewOriginalTxOutput(*consensus.BTMAssetID, 5000, []byte("controlProgram2"), nil),
+ },
+ }),
+ },
+ },
+ checkpoint: &state.Checkpoint{
+ Rewards: map[string]uint64{
+ hex.EncodeToString([]byte("controlProgram1")): 5000,
+ hex.EncodeToString([]byte("controlProgram2")): 5000},
+ },
+ err: nil,
+ },
+ {
+ block: &types.Block{
+ BlockHeader: types.BlockHeader{},
+ Transactions: []*types.Tx{},
+ },
+ checkpoint: &state.Checkpoint{
+ Rewards: map[string]uint64{"controlProgram": 5000},
+ },
+ err: ErrWrongCoinbaseTransaction,
},
}
- block := new(types.Block)
for i, c := range cases {
- block.Transactions = c.txs
- if err := checkCoinbaseAmount(types.MapBlock(block), c.amount); rootErr(err) != c.err {
- t.Errorf("case %d got error %s, want %s", i, err, c.err)
+ if err := checkCoinbaseAmount(types.MapBlock(c.block), c.checkpoint); rootErr(err) != c.err {
+ t.Errorf("case %d got error %v, want %v", i, err, c.err)
}
}
}
cp, _ := vmutil.DefaultCoinbaseProgram()
converter := func(prog []byte) ([]byte, error) { return nil, nil }
cases := []struct {
- desc string
- block *bc.Block
- parent *state.BlockNode
- err error
+ desc string
+ block *bc.Block
+ parent *state.BlockNode
+ checkpoint *state.Checkpoint
+ err error
}{
{
desc: "The calculated transaction merkel root hash is not equals to the hash of the block header (blocktest#1009)",
ID: bc.Hash{V0: 1},
BlockHeader: &bc.BlockHeader{
Version: 1,
- Height: 1,
+ Height: state.BlocksOfEpoch + 1,
Timestamp: 1523358600,
PreviousBlockId: &bc.Hash{V0: 0},
TransactionsRoot: &bc.Hash{V0: 1},
Version: 1,
SerializedSize: 1,
Inputs: []*types.TxInput{types.NewCoinbaseInput(nil)},
- Outputs: []*types.TxOutput{types.NewOriginalTxOutput(*consensus.BTMAssetID, 41250000000, cp, nil)},
+ Outputs: []*types.TxOutput{
+ types.NewOriginalTxOutput(*consensus.BTMAssetID, 41250000000, cp, nil),
+ },
}),
},
},
parent: &state.BlockNode{
Version: 1,
- Height: 0,
+ Height: state.BlocksOfEpoch,
Timestamp: 1523352600,
Hash: bc.Hash{V0: 0},
},
+ checkpoint: &state.Checkpoint{
+ Rewards: map[string]uint64{hex.EncodeToString(cp): 41250000000}},
err: errMismatchedMerkleRoot,
},
{
ID: bc.Hash{V0: 1},
BlockHeader: &bc.BlockHeader{
Version: 1,
- Height: 1,
+ Height: state.BlocksOfEpoch + 1,
Timestamp: 1523358600,
PreviousBlockId: &bc.Hash{V0: 0},
TransactionsRoot: &bc.Hash{V0: 6294987741126419124, V1: 12520373106916389157, V2: 5040806596198303681, V3: 1151748423853876189},
Version: 1,
SerializedSize: 1,
Inputs: []*types.TxInput{types.NewCoinbaseInput(nil)},
- Outputs: []*types.TxOutput{types.NewOriginalTxOutput(*consensus.BTMAssetID, 41250000000, cp, nil)},
+ Outputs: []*types.TxOutput{
+ types.NewOriginalTxOutput(*consensus.BTMAssetID, 41250000000, cp, nil),
+ },
}),
},
},
parent: &state.BlockNode{
Version: 1,
- Height: 0,
+ Height: state.BlocksOfEpoch,
Timestamp: 1523352600,
Hash: bc.Hash{V0: 0},
},
- err: errMismatchedMerkleRoot,
- },
- {
- desc: "the coinbase amount is less than the real coinbase amount (txtest#1014)",
- block: &bc.Block{
- ID: bc.Hash{V0: 1},
- BlockHeader: &bc.BlockHeader{
- Version: 1,
- Height: 1,
- Timestamp: 1523358600,
- PreviousBlockId: &bc.Hash{V0: 0},
- },
- Transactions: []*bc.Tx{
- types.MapTx(&types.TxData{
- Version: 1,
- SerializedSize: 1,
- Inputs: []*types.TxInput{types.NewCoinbaseInput(nil)},
- Outputs: []*types.TxOutput{types.NewOriginalTxOutput(*consensus.BTMAssetID, 41250000000, cp, nil)},
- }),
- types.MapTx(&types.TxData{
- Version: 1,
- SerializedSize: 1,
- Inputs: []*types.TxInput{types.NewSpendInput([][]byte{}, *newHash(8), *consensus.BTMAssetID, 100000000, 0, cp, nil)},
- Outputs: []*types.TxOutput{types.NewOriginalTxOutput(*consensus.BTMAssetID, 90000000, cp, nil)},
- }),
- },
+ checkpoint: &state.Checkpoint{
+ Rewards: map[string]uint64{hex.EncodeToString(cp): 41250000000},
},
- parent: &state.BlockNode{
- Version: 1,
- Height: 0,
- Timestamp: 1523352600,
- Hash: bc.Hash{V0: 0},
- },
- err: ErrWrongCoinbaseTransaction,
+ err: errMismatchedMerkleRoot,
},
}
for i, c := range cases {
- err := ValidateBlock(c.block, c.parent, converter)
+ err := ValidateBlock(c.block, c.parent, c.checkpoint, converter)
if rootErr(err) != c.err {
t.Errorf("case #%d (%s) got error %s, want %s", i, c.desc, err, c.err)
}
},
}
+ checkpoint := &state.Checkpoint{
+ Rewards: nil,
+ }
+
for i := 0; i < 100; i++ {
block.Transactions = append(block.Transactions, types.MapTx(&types.TxData{
Version: 1,
}))
}
- if err := ValidateBlock(block, parent, converter); err != errOverBlockLimit {
+ if err := ValidateBlock(block, parent, checkpoint, converter); err != errOverBlockLimit {
t.Errorf("got error %s, want %s", err, errOverBlockLimit)
}
}
t.Error(err)
}
}
- if err := store.SaveChainStatus(node, utxoViewpoint, contractView,0, &bc.Hash{}); err != nil {
+ if err := store.SaveChainStatus(node, utxoViewpoint, contractView, 0, &bc.Hash{}); err != nil {
t.Error(err)
}