Skip to content

Commit 40c28ba

Browse files
committed
core: add full block - flow test
1 parent afff9f7 commit 40c28ba

File tree

1 file changed

+171
-1
lines changed

1 file changed

+171
-1
lines changed

core/blockchain_test.go

+171-1
Original file line numberDiff line numberDiff line change
@@ -4609,7 +4609,7 @@ func addNewFeeMarketCallContractTx(t testing.TB, contractAddress common.Address,
46094609
tx, _ = types.SignNewTx(testKey, signer, &types.LegacyTx{
46104610
Nonce: nonce,
46114611
GasPrice: gasPrice,
4612-
Gas: 150000,
4612+
Gas: 160000,
46134613
To: &contractAddress,
46144614
Data: data,
46154615
})
@@ -4760,3 +4760,173 @@ func BenchmarkSatoshiFeeMarket(b *testing.B) {
47604760
b.StopTimer()
47614761
}
47624762
}
4763+
4764+
func TestFullBlock(t *testing.T) {
4765+
// Set up logger to write to stdout at trace level
4766+
// glogger := log.NewGlogHandler(log.NewTerminalHandler(os.Stdout, false))
4767+
// glogger.Verbosity(log.LevelTrace)
4768+
// log.SetDefault(log.NewLogger(glogger))
4769+
4770+
blockGasLimit := uint64(50_000_000)
4771+
4772+
// rewardRecipientMap[blockNumber][rewardRecipient] = numberOfTxs
4773+
rewardRecipientMap := make(map[uint64]map[common.Address]uint64)
4774+
remainingGasPoolMap := make(map[uint64]uint64)
4775+
4776+
createGenRandomFn := func(withConfig bool) func(*params.ChainConfig, *BlockChain, common.Address) func(int, *BlockGen) {
4777+
return func(config *params.ChainConfig, chain *BlockChain, feeMarketAddress common.Address) func(i int, gen *BlockGen) {
4778+
return func(i int, gen *BlockGen) {
4779+
signer := types.LatestSigner(config)
4780+
fee := big.NewInt(1)
4781+
4782+
gen.SetCoinbase(common.Address{1})
4783+
4784+
blockNumber := gen.Number().Uint64()
4785+
rewardRecipientMap[blockNumber] = make(map[common.Address]uint64)
4786+
4787+
for y := 0; gen.gasPool.Gas() > 500_000; y++ {
4788+
var counterContractAddress common.Address
4789+
rewardRecipient := common.BytesToAddress(crypto.Keccak256([]byte(fmt.Sprintf("recipient-%d", y))))
4790+
4791+
// Deploy counter contract
4792+
nonce := gen.TxNonce(testAddr)
4793+
_, counterContractAddress = addNewFeeMarketTestContractTx(t, nonce, fee, chain, gen, signer)
4794+
4795+
// Add configuration only if enabled
4796+
if withConfig {
4797+
addFeeMarketConfigurationTx(t, feeMarketAddress, counterContractAddress, rewardRecipient, gen.TxNonce(testAddr), fee, chain, gen, signer)
4798+
}
4799+
4800+
// Add transactions until the block is full
4801+
for z := 0; gen.gasPool.Gas() > 500_000 && z < 4; z++ {
4802+
addNewFeeMarketCallContractTx(t, counterContractAddress, gen.TxNonce(testAddr), fee, chain, gen, signer)
4803+
rewardRecipientMap[blockNumber][rewardRecipient]++
4804+
}
4805+
}
4806+
4807+
remainingGasPoolMap[blockNumber] = gen.gasPool.Gas()
4808+
}
4809+
}
4810+
}
4811+
4812+
chainTesterFn := func(withConfig bool) func(chain *BlockChain, blocks []*types.Block) {
4813+
return func(chain *BlockChain, blocks []*types.Block) {
4814+
stateDB, err := chain.State()
4815+
if err != nil {
4816+
t.Fatalf("failed to get state: %v", err)
4817+
}
4818+
4819+
for _, block := range blocks {
4820+
// txs := block.Transactions()
4821+
receipts := chain.GetReceiptsByHash(block.Hash())
4822+
4823+
fmt.Println("Block number:", block.Number().Uint64(), "txs:", len(receipts), "withConfig:", withConfig)
4824+
4825+
// Calculate full gas used from receipts
4826+
txGasUsed := uint64(0)
4827+
for _, receipt := range receipts {
4828+
// tx := txs[idx]
4829+
// fmt.Println("receipt:", "gasUsed:", receipt.GasUsed, "toAddr:", tx.To(), "status:", receipt.Status, "logs:", len(receipt.Logs), "contractAddr:", receipt.ContractAddress, "effectiveGasPrice:", receipt.EffectiveGasPrice)
4830+
txGasUsed += receipt.GasUsed
4831+
4832+
if receipt.Status == types.ReceiptStatusFailed {
4833+
t.Errorf("transaction failed tx_hash: %s, status: %d, block number: %d", receipt.TxHash.Hex(), receipt.Status, block.Number().Uint64())
4834+
}
4835+
}
4836+
4837+
// Check if block gas used reports the sum of all txs gas used
4838+
if block.GasUsed() != txGasUsed {
4839+
t.Fatalf("block.GasUsed() %d doesn't match txGasUsed %d", block.GasUsed(), txGasUsed)
4840+
}
4841+
4842+
// Calculate the total amount of fees paid as fee market rewards
4843+
distributedAmount := big.NewInt(0)
4844+
if withConfig {
4845+
blockRecepients := rewardRecipientMap[block.Number().Uint64()]
4846+
for recipient, numberOfTxs := range blockRecepients {
4847+
// TODO: make gas 100000 configurable
4848+
expect := new(big.Int).Mul(big.NewInt(int64(numberOfTxs)), big.NewInt(int64(100000)))
4849+
4850+
distributedAmount.Add(distributedAmount, expect)
4851+
4852+
actual := stateDB.GetBalance(recipient)
4853+
require.Equal(t, actual.Uint64(), expect.Uint64(),
4854+
fmt.Sprintf("recipient (%s) balance %d is different that expected fee market reward %d (numberOfTxs: %d)", recipient.Hex(), actual.Uint64(), expect.Uint64(), numberOfTxs))
4855+
}
4856+
}
4857+
4858+
// Check if validator reward receives:
4859+
// - all txs profit if there is no fee market configuration
4860+
// - txs profit excluding the fee market rewards if there is a fee market configuration
4861+
validatorRewardU64 := stateDB.GetBalance(params.SystemAddress).Uint64()
4862+
if withConfig {
4863+
if validatorRewardU64 == txGasUsed {
4864+
t.Errorf("validator (%d) shouldn't receive all txs fees, as some has been distributed to fee market recipients (txGasUsed: %d)", validatorRewardU64, txGasUsed)
4865+
}
4866+
} else {
4867+
if validatorRewardU64 != txGasUsed {
4868+
t.Errorf("validator (%d) should receive all txs fees", validatorRewardU64)
4869+
}
4870+
}
4871+
4872+
// Get the remaining gas in the pool
4873+
remainingBlockPoolGas := remainingGasPoolMap[block.Number().Uint64()]
4874+
distributedAmountU64 := distributedAmount.Uint64()
4875+
4876+
// Check if block gas pool expands as expected to fit more transactions when distributed gas exists (aka ghost gas)
4877+
if withConfig {
4878+
if txGasUsed-distributedAmountU64+remainingBlockPoolGas != blockGasLimit {
4879+
t.Fatalf("block gas limit %d doesn't fit txGasUsed %d, with included distributed gas %d", blockGasLimit, txGasUsed, distributedAmountU64)
4880+
}
4881+
} else {
4882+
if txGasUsed+remainingBlockPoolGas != blockGasLimit {
4883+
t.Fatalf("block gas limit %d with remaining gas %d is not equal to txGasUsed %d", blockGasLimit, remainingBlockPoolGas, txGasUsed)
4884+
}
4885+
}
4886+
}
4887+
t.Fail()
4888+
}
4889+
}
4890+
4891+
t.Run("WithConfiguration", func(t *testing.T) {
4892+
testFeeMarketBlock(t, blockGasLimit, createGenRandomFn(true), chainTesterFn(true))
4893+
})
4894+
4895+
t.Run("WithoutConfiguration", func(t *testing.T) {
4896+
testFeeMarketBlock(t, blockGasLimit, createGenRandomFn(false), chainTesterFn(false))
4897+
})
4898+
}
4899+
4900+
func testFeeMarketBlock(t *testing.T, gasLimit uint64, genFn func(config *params.ChainConfig, chain *BlockChain, feeMarketAddress common.Address) func(i int, gen *BlockGen), chainTesterFn func(chain *BlockChain, blocks []*types.Block)) {
4901+
config := params.SatoshiTestChainConfig
4902+
gspec := &Genesis{
4903+
Config: config,
4904+
GasLimit: gasLimit,
4905+
Alloc: types.GenesisAlloc{
4906+
testAddr: {Balance: new(big.Int).SetUint64(15 * params.Ether)},
4907+
},
4908+
}
4909+
4910+
feeMarketAddress, feeMarketAccount := getFeeMarketGenesisAlloc(2, 2, 1000000)
4911+
gspec.Alloc[feeMarketAddress] = feeMarketAccount
4912+
4913+
// Initialize blockchain
4914+
frdir := t.TempDir()
4915+
db, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "", false, false, false, false, false)
4916+
if err != nil {
4917+
t.Fatalf("failed to create database with ancient backend")
4918+
}
4919+
engine := &mockSatoshi{}
4920+
chain, _ := NewBlockChain(db, nil, gspec, nil, engine, vm.Config{}, nil, nil)
4921+
4922+
// Generate chain blocks
4923+
_, bs, _ := GenerateChainWithGenesis(gspec, engine, 1, genFn(config, chain, feeMarketAddress))
4924+
4925+
// Insert chain
4926+
if _, err := chain.InsertChain(bs); err != nil {
4927+
t.Fatalf("failed to insert chain: %v", err)
4928+
}
4929+
4930+
// Verify the chain
4931+
chainTesterFn(chain, bs)
4932+
}

0 commit comments

Comments
 (0)