github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/fvm/evm/handler/blockstore_test.go (about) 1 package handler_test 2 3 import ( 4 "math/big" 5 "testing" 6 7 gethCommon "github.com/onflow/go-ethereum/common" 8 gethRLP "github.com/onflow/go-ethereum/rlp" 9 "github.com/stretchr/testify/require" 10 11 "github.com/onflow/flow-go/fvm/evm/handler" 12 "github.com/onflow/flow-go/fvm/evm/testutils" 13 "github.com/onflow/flow-go/fvm/evm/types" 14 "github.com/onflow/flow-go/model/flow" 15 ) 16 17 func TestBlockStore(t *testing.T) { 18 19 testutils.RunWithTestBackend(t, func(backend *testutils.TestBackend) { 20 testutils.RunWithTestFlowEVMRootAddress(t, backend, func(root flow.Address) { 21 bs := handler.NewBlockStore(backend, root) 22 23 // check gensis block 24 b, err := bs.LatestBlock() 25 require.NoError(t, err) 26 require.Equal(t, types.GenesisBlock, b) 27 h, err := bs.BlockHash(0) 28 require.NoError(t, err) 29 require.Equal(t, types.GenesisBlockHash, h) 30 31 // test block proposal from genesis 32 bp, err := bs.BlockProposal() 33 require.NoError(t, err) 34 require.Equal(t, uint64(1), bp.Height) 35 expectedParentHash, err := types.GenesisBlock.Hash() 36 require.NoError(t, err) 37 require.Equal(t, expectedParentHash, bp.ParentBlockHash) 38 39 // commit block proposal 40 supply := big.NewInt(100) 41 bp.TotalSupply = supply 42 err = bs.CommitBlockProposal() 43 require.NoError(t, err) 44 b, err = bs.LatestBlock() 45 require.NoError(t, err) 46 require.Equal(t, supply, b.TotalSupply) 47 require.Equal(t, uint64(1), b.Height) 48 bp, err = bs.BlockProposal() 49 require.NoError(t, err) 50 require.Equal(t, uint64(2), bp.Height) 51 52 // check block hashes 53 // genesis 54 h, err = bs.BlockHash(0) 55 require.NoError(t, err) 56 require.Equal(t, types.GenesisBlockHash, h) 57 58 // block 1 59 h, err = bs.BlockHash(1) 60 require.NoError(t, err) 61 expected, err := b.Hash() 62 require.NoError(t, err) 63 require.Equal(t, expected, h) 64 65 // block 2 66 h, err = bs.BlockHash(2) 67 require.NoError(t, err) 68 require.Equal(t, gethCommon.Hash{}, h) 69 }) 70 71 }) 72 73 } 74 75 // This test reproduces a state before a breaking change on the Block type, 76 // which added a timestamp and total gas used, 77 // then it adds new blocks and makes sure the retrival 78 // and storage of blocks works as it should, the breaking change was introduced 79 // in this PR https://github.com/onflow/flow-go/pull/5660 80 func TestBlockStore_AddedTimestamp(t *testing.T) { 81 testutils.RunWithTestBackend(t, func(backend *testutils.TestBackend) { 82 testutils.RunWithTestFlowEVMRootAddress(t, backend, func(root flow.Address) { 83 84 bs := handler.NewBlockStore(backend, root) 85 86 // block type before breaking change (no timestamp and total gas used) 87 type oldBlockV1 struct { 88 ParentBlockHash gethCommon.Hash 89 Height uint64 90 UUIDIndex uint64 91 TotalSupply uint64 92 StateRoot gethCommon.Hash 93 ReceiptRoot gethCommon.Hash 94 TransactionHashes []gethCommon.Hash 95 } 96 97 g := types.GenesisBlock 98 h, err := g.Hash() 99 require.NoError(t, err) 100 101 b := oldBlockV1{ 102 ParentBlockHash: h, 103 Height: 1, 104 ReceiptRoot: g.ReceiptRoot, 105 UUIDIndex: 123, 106 TotalSupply: 1, 107 StateRoot: h, 108 TransactionHashes: []gethCommon.Hash{h}, 109 } 110 blockBytes, err := gethRLP.EncodeToBytes(b) 111 require.NoError(t, err) 112 113 // store a block without timestamp, simulate existing state before the breaking change 114 err = backend.SetValue(root[:], []byte(handler.BlockStoreLatestBlockKey), blockBytes) 115 require.NoError(t, err) 116 117 block, err := bs.LatestBlock() 118 require.NoError(t, err) 119 120 require.Empty(t, block.Timestamp) 121 require.Empty(t, block.TotalGasUsed) 122 require.Equal(t, b.Height, block.Height) 123 require.Equal(t, b.ParentBlockHash, block.ParentBlockHash) 124 require.Equal(t, b.ReceiptRoot, block.ReceiptRoot) 125 126 // added timestamp 127 type oldBlockV2 struct { 128 ParentBlockHash gethCommon.Hash 129 Height uint64 130 Timestamp uint64 131 TotalSupply *big.Int 132 ReceiptRoot gethCommon.Hash 133 TransactionHashes []gethCommon.Hash 134 } 135 136 b2 := oldBlockV2{ 137 ParentBlockHash: h, 138 Height: 2, 139 TotalSupply: g.TotalSupply, 140 ReceiptRoot: g.ReceiptRoot, 141 Timestamp: 1, 142 } 143 blockBytes2, err := gethRLP.EncodeToBytes(b2) 144 require.NoError(t, err) 145 146 // store a block without timestamp, simulate existing state before the breaking change 147 err = backend.SetValue(root[:], []byte(handler.BlockStoreLatestBlockKey), blockBytes2) 148 require.NoError(t, err) 149 150 block2, err := bs.LatestBlock() 151 require.NoError(t, err) 152 153 require.Empty(t, block2.TotalGasUsed) 154 require.Equal(t, b2.Height, block2.Height) 155 require.Equal(t, b2.ParentBlockHash, block2.ParentBlockHash) 156 require.Equal(t, b2.TotalSupply, block2.TotalSupply) 157 require.Equal(t, b2.ReceiptRoot, block2.ReceiptRoot) 158 require.Equal(t, b2.Timestamp, block2.Timestamp) 159 160 bp, err := bs.BlockProposal() 161 require.NoError(t, err) 162 163 blockBytes, err = bp.ToBytes() 164 require.NoError(t, err) 165 166 err = backend.SetValue(root[:], []byte(handler.BlockStoreLatestBlockKey), blockBytes) 167 require.NoError(t, err) 168 169 bb, err := bs.LatestBlock() 170 require.NoError(t, err) 171 require.NotNil(t, bb.ParentBlockHash) 172 require.NotNil(t, bb.TotalGasUsed) 173 require.NotNil(t, bb.Timestamp) 174 require.Equal(t, b2.Height+1, bb.Height) 175 }) 176 }) 177 }