diff --git a/core/block_validator.go b/core/block_validator.go index dff3e8dc1f1e..fa01fa8e1a9f 100644 --- a/core/block_validator.go +++ b/core/block_validator.go @@ -97,13 +97,20 @@ func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateD if receiptSha != header.ReceiptHash { return fmt.Errorf("invalid receipt root hash (remote: %x local: %x)", header.ReceiptHash, receiptSha) } + + // validate engine specific; ethash.engine validate the fees and rewards + err := v.engine.ValidateEngineSpecific(v.bc.chainConfig, header, fees, finalizedOutput) + if err != nil { + return err + } + // Validate the state root against the received state root and throw // an error if they don't match. if root := statedb.IntermediateRoot(v.config.IsEIP158(header.Number)); header.Root != root { return fmt.Errorf("invalid merkle root (remote: %x local: %x)", header.Root, root) } - return v.engine.ValidateEngineSpecific(v.bc.chainConfig, header, fees, finalizedOutput) + return nil } // CalcGasLimit computes the gas limit of the next block after parent. It aims diff --git a/core/chain_makers.go b/core/chain_makers.go index a8a0437b9f7c..0f4dea2c9b06 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -104,7 +104,13 @@ func (b *BlockGen) AddTxWithChain(bc *BlockChain, tx *types.Transaction) { b.SetCoinbase(common.Address{}) } b.statedb.Prepare(tx.Hash(), len(b.txs)) - receipt, err := ApplyTransaction(b.config, bc, &b.header.Coinbase, b.gasPool, b.statedb, b.header, tx, &b.header.GasUsed, b.header.Fees, vm.Config{}) + var fees *big.Int + if b.header.Fees != nil { + fees = b.header.Fees // wemix block has `Fees` field + } else { + fees = new(big.Int) + } + receipt, err := ApplyTransaction(b.config, bc, &b.header.Coinbase, b.gasPool, b.statedb, b.header, tx, &b.header.GasUsed, fees, vm.Config{}) if err != nil { panic(err) } @@ -303,6 +309,7 @@ func makeHeader(chain consensus.ChainReader, parent *types.Block, state *state.S }), GasLimit: parent.GasLimit(), Number: new(big.Int).Add(parent.Number(), common.Big1), + Fees: new(big.Int), Time: time, } if chain.Config().IsLondon(header.Number) { diff --git a/wemix/rewards_test.go b/wemix/rewards_test.go index 3b4d33e4c47e..f8a6fff8c133 100644 --- a/wemix/rewards_test.go +++ b/wemix/rewards_test.go @@ -3,14 +3,18 @@ package wemix import ( + "bytes" + "crypto/ecdsa" "encoding/json" "math/big" + "strings" "testing" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/params" @@ -175,51 +179,51 @@ func TestDistributeRewards(t *testing.T) { } } -func calculateRewardsForTest(config *params.ChainConfig, num, fees *big.Int, addBalance func(common.Address, *big.Int)) (*common.Address, []byte, error) { - rp := &rewardParameters{ - rewardAmount: big.NewInt(1e18), - staker: &common.Address{0x11}, - ecoSystem: &common.Address{0x22}, - maintenance: &common.Address{0x33}, - feeCollector: &common.Address{0x44}, - members: []*wemixMember{ - { - Staker: common.HexToAddress("0x02b4b2d83786c8ee315db2ddac704794850d2149"), - Reward: common.HexToAddress("0x02b4b2d83786c8ee315db2ddac704794850d2149"), - Stake: hexToBigInt("0x1a784379d99db42000000"), - }, - { - Staker: common.HexToAddress("0xb16d2494fddfa4c000deaf642d47673e5ca74e07"), - Reward: common.HexToAddress("0xb16d2494fddfa4c000deaf642d47673e5ca74e07"), - Stake: hexToBigInt("0xe8ef1e96ae3897800000"), - }, - { - Staker: common.HexToAddress("0x452893ed818c0e3ea6f415aeab8ef08778087fc6"), - Reward: common.HexToAddress("0x452893ed818c0e3ea6f415aeab8ef08778087fc6"), - Stake: hexToBigInt("0xc92b9a6adc4825c00000"), - }, - }, - blocksPer: 1, - distributionMethod: []*big.Int{big.NewInt(4000), big.NewInt(1000), big.NewInt(2500), big.NewInt(2500)}, +func makeCalculateRewardFunc(rp *rewardParameters) func(config *params.ChainConfig, num, fees *big.Int, addBalance func(common.Address, *big.Int)) (*common.Address, []byte, error) { + return func(config *params.ChainConfig, num, fees *big.Int, addBalance func(common.Address, *big.Int)) (*common.Address, []byte, error) { + return calculateRewardsWithParams(config, rp, num, fees, addBalance) } +} - return calculateRewardsWithParams(config, rp, num, fees, addBalance) +func makeSignBlockFunc(privateKey *ecdsa.PrivateKey) func(height *big.Int, hash common.Hash) (common.Address, []byte, error) { + return func(height *big.Int, hash common.Hash) (coinbase common.Address, sig []byte, err error) { + data := append(height.Bytes(), hash.Bytes()...) + data = crypto.Keccak256(data) + sig, _ = crypto.Sign(data, privateKey) + return crypto.PubkeyToAddress(privateKey.PublicKey), sig, nil + } +} + +func verifyBlockSigForTest(height *big.Int, coinbase common.Address, nodeId []byte, hash common.Hash, sig []byte, checkMinerLimit bool) bool { + var data []byte + data = append(height.Bytes(), hash.Bytes()...) + data = crypto.Keccak256(data) + pubKey, err := crypto.SigToPub(data, sig) + if err != nil { + return false + } + signer := crypto.PubkeyToAddress(*pubKey) + if err != nil || !bytes.Equal(coinbase.Bytes(), signer.Bytes()) { + return false + } + return true } func TestRewardValidation(t *testing.T) { // use wemix consensus params.ConsensusMethod = params.ConsensusPoA - wemixminer.CalculateRewardsFunc = calculateRewardsForTest var ( db = rawdb.NewMemoryDatabase() key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") address = crypto.PubkeyToAddress(key.PublicKey) - funds = big.NewInt(1000000000) + funds = big.NewInt(100000000000000) deleteAddr = common.Address{1} gspec = &core.Genesis{ Config: ¶ms.ChainConfig{ - ChainID: big.NewInt(1), + ChainID: big.NewInt(1), + LondonBlock: common.Big0, + BriocheBlock: common.Big0, Brioche: ¶ms.BriocheConfig{ BlockReward: big.NewInt(100), FirstHalvingBlock: big.NewInt(0), @@ -231,18 +235,67 @@ func TestRewardValidation(t *testing.T) { Alloc: core.GenesisAlloc{address: {Balance: funds}, deleteAddr: {Balance: big.NewInt(0)}}, } genesis = gspec.MustCommit(db) + signer = types.LatestSigner(gspec.Config) ) + rp := &rewardParameters{ + rewardAmount: big.NewInt(1e18), + staker: &common.Address{0x11}, + ecoSystem: &common.Address{0x22}, + maintenance: &common.Address{0x33}, + feeCollector: &common.Address{0x44}, + members: []*wemixMember{ + { + Staker: common.HexToAddress("0x02b4b2d83786c8ee315db2ddac704794850d2149"), + Reward: common.HexToAddress("0x02b4b2d83786c8ee315db2ddac704794850d2149"), + Stake: hexToBigInt("0x1a784379d99db42000000"), + }, + { + Staker: common.HexToAddress("0xb16d2494fddfa4c000deaf642d47673e5ca74e07"), + Reward: common.HexToAddress("0xb16d2494fddfa4c000deaf642d47673e5ca74e07"), + Stake: hexToBigInt("0xe8ef1e96ae3897800000"), + }, + { + Staker: common.HexToAddress("0x452893ed818c0e3ea6f415aeab8ef08778087fc6"), + Reward: common.HexToAddress("0x452893ed818c0e3ea6f415aeab8ef08778087fc6"), + Stake: hexToBigInt("0xc92b9a6adc4825c00000"), + }, + }, + blocksPer: 1, + distributionMethod: []*big.Int{big.NewInt(4000), big.NewInt(1000), big.NewInt(2500), big.NewInt(2500)}, + } + + wemixminer.CalculateRewardsFunc = makeCalculateRewardFunc(rp) + wemixminer.SignBlockFunc = makeSignBlockFunc(key) + wemixminer.VerifyBlockSigFunc = verifyBlockSigForTest + blockchain, _ := core.NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) defer blockchain.Stop() - gspec.Config.Brioche.BlockReward = big.NewInt(200) - // TODO: core.GenerateChain does not make a wemix block including Fees, Rewards etc. - // TODO: implement wemix.GenerateChain function - blocks, _ := core.GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 1, nil) + byzantineConfig := ¶ms.ChainConfig{ + ChainID: gspec.Config.ChainID, + LondonBlock: gspec.Config.LondonBlock, + BriocheBlock: gspec.Config.BriocheBlock, + Brioche: ¶ms.BriocheConfig{ + BlockReward: big.NewInt(200), // different reward!! + FirstHalvingBlock: gspec.Config.Brioche.FirstHalvingBlock, + HalvingPeriod: gspec.Config.Brioche.HalvingPeriod, + NoRewardHereafter: gspec.Config.Brioche.NoRewardHereafter, + HalvingTimes: gspec.Config.Brioche.HalvingTimes, + HalvingRate: gspec.Config.Brioche.HalvingRate, + }} + blocks, _ := core.GenerateChain(byzantineConfig, genesis, ethash.NewFaker(), db, 1, func(i int, gen *core.BlockGen) { + tx, err := types.SignTx(types.NewTransaction(gen.TxNonce(address), common.Address{0x00}, big.NewInt(1), params.TxGas, gen.BaseFee(), nil), signer, key) + if err != nil { + panic(err) + } + gen.AddTx(tx) + }) if _, err := blockchain.InsertChain(blocks); err != nil { - t.Fatal(err) + if !strings.HasPrefix(err.Error(), "invalid rewards") { + t.Fatal(err) + } } }