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  }