From 918174231233a7e7c0a746b0d14db6794a6ee14d Mon Sep 17 00:00:00 2001 From: Adrian Sutton Date: Mon, 17 Apr 2023 10:44:58 +1000 Subject: [PATCH] op-program: Extract stub oracles to a reusable test package --- op-program/client/l1/cache_test.go | 27 ++--- op-program/client/l1/client_test.go | 23 +++-- op-program/client/l1/stub_oracle_test.go | 54 ---------- op-program/client/l1/test/stub_oracle.go | 54 ++++++++++ op-program/client/l2/cache_test.go | 19 ++-- op-program/client/l2/db_test.go | 26 +++-- op-program/client/l2/engine_backend_test.go | 5 +- op-program/client/l2/stub_oracle_test.go | 94 ----------------- op-program/client/l2/test/stub_oracle.go | 107 ++++++++++++++++++++ 9 files changed, 212 insertions(+), 197 deletions(-) delete mode 100644 op-program/client/l1/stub_oracle_test.go create mode 100644 op-program/client/l1/test/stub_oracle.go delete mode 100644 op-program/client/l2/stub_oracle_test.go create mode 100644 op-program/client/l2/test/stub_oracle.go diff --git a/op-program/client/l1/cache_test.go b/op-program/client/l1/cache_test.go index 8c71e5c1417e6..b2b20b64f7c2f 100644 --- a/op-program/client/l1/cache_test.go +++ b/op-program/client/l1/cache_test.go @@ -6,6 +6,7 @@ import ( "github.com/ethereum-optimism/optimism/op-node/eth" "github.com/ethereum-optimism/optimism/op-node/testutils" + "github.com/ethereum-optimism/optimism/op-program/client/l1/test" "github.com/stretchr/testify/require" ) @@ -14,37 +15,37 @@ var _ Oracle = (*CachingOracle)(nil) func TestCachingOracle_HeaderByBlockHash(t *testing.T) { rng := rand.New(rand.NewSource(1)) - stub := newStubOracle(t) + stub := test.NewStubOracle(t) oracle := NewCachingOracle(stub) block := testutils.RandomBlockInfo(rng) // Initial call retrieves from the stub - stub.blocks[block.Hash()] = block + stub.Blocks[block.Hash()] = block result := oracle.HeaderByBlockHash(block.Hash()) require.Equal(t, block, result) // Later calls should retrieve from cache - delete(stub.blocks, block.Hash()) + delete(stub.Blocks, block.Hash()) result = oracle.HeaderByBlockHash(block.Hash()) require.Equal(t, block, result) } func TestCachingOracle_TransactionsByBlockHash(t *testing.T) { rng := rand.New(rand.NewSource(1)) - stub := newStubOracle(t) + stub := test.NewStubOracle(t) oracle := NewCachingOracle(stub) block, _ := testutils.RandomBlock(rng, 3) // Initial call retrieves from the stub - stub.blocks[block.Hash()] = eth.BlockToInfo(block) - stub.txs[block.Hash()] = block.Transactions() + stub.Blocks[block.Hash()] = eth.BlockToInfo(block) + stub.Txs[block.Hash()] = block.Transactions() actualBlock, actualTxs := oracle.TransactionsByBlockHash(block.Hash()) require.Equal(t, eth.BlockToInfo(block), actualBlock) require.Equal(t, block.Transactions(), actualTxs) // Later calls should retrieve from cache - delete(stub.blocks, block.Hash()) - delete(stub.txs, block.Hash()) + delete(stub.Blocks, block.Hash()) + delete(stub.Txs, block.Hash()) actualBlock, actualTxs = oracle.TransactionsByBlockHash(block.Hash()) require.Equal(t, eth.BlockToInfo(block), actualBlock) require.Equal(t, block.Transactions(), actualTxs) @@ -52,20 +53,20 @@ func TestCachingOracle_TransactionsByBlockHash(t *testing.T) { func TestCachingOracle_ReceiptsByBlockHash(t *testing.T) { rng := rand.New(rand.NewSource(1)) - stub := newStubOracle(t) + stub := test.NewStubOracle(t) oracle := NewCachingOracle(stub) block, rcpts := testutils.RandomBlock(rng, 3) // Initial call retrieves from the stub - stub.blocks[block.Hash()] = eth.BlockToInfo(block) - stub.rcpts[block.Hash()] = rcpts + stub.Blocks[block.Hash()] = eth.BlockToInfo(block) + stub.Rcpts[block.Hash()] = rcpts actualBlock, actualRcpts := oracle.ReceiptsByBlockHash(block.Hash()) require.Equal(t, eth.BlockToInfo(block), actualBlock) require.EqualValues(t, rcpts, actualRcpts) // Later calls should retrieve from cache - delete(stub.blocks, block.Hash()) - delete(stub.rcpts, block.Hash()) + delete(stub.Blocks, block.Hash()) + delete(stub.Rcpts, block.Hash()) actualBlock, actualRcpts = oracle.ReceiptsByBlockHash(block.Hash()) require.Equal(t, eth.BlockToInfo(block), actualBlock) require.EqualValues(t, rcpts, actualRcpts) diff --git a/op-program/client/l1/client_test.go b/op-program/client/l1/client_test.go index cc8eae3f1ce38..4cb4462330d78 100644 --- a/op-program/client/l1/client_test.go +++ b/op-program/client/l1/client_test.go @@ -9,6 +9,7 @@ import ( "github.com/ethereum-optimism/optimism/op-node/rollup/derive" "github.com/ethereum-optimism/optimism/op-node/testlog" "github.com/ethereum-optimism/optimism/op-node/testutils" + "github.com/ethereum-optimism/optimism/op-program/client/l1/test" "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" @@ -24,7 +25,7 @@ func TestInfoByHash(t *testing.T) { client, oracle := newClient(t) hash := common.HexToHash("0xAABBCC") expected := &testutils.MockBlockInfo{} - oracle.blocks[hash] = expected + oracle.Blocks[hash] = expected info, err := client.InfoByHash(context.Background(), hash) require.NoError(t, err) @@ -35,7 +36,7 @@ func TestL1BlockRefByHash(t *testing.T) { client, oracle := newClient(t) hash := common.HexToHash("0xAABBCC") header := &testutils.MockBlockInfo{} - oracle.blocks[hash] = header + oracle.Blocks[hash] = header expected := eth.InfoToL1BlockRef(header) ref, err := client.L1BlockRefByHash(context.Background(), hash) @@ -50,8 +51,8 @@ func TestFetchReceipts(t *testing.T) { expectedReceipts := types.Receipts{ &types.Receipt{}, } - oracle.blocks[hash] = expectedInfo - oracle.rcpts[hash] = expectedReceipts + oracle.Blocks[hash] = expectedInfo + oracle.Rcpts[hash] = expectedReceipts info, rcpts, err := client.FetchReceipts(context.Background(), hash) require.NoError(t, err) @@ -66,8 +67,8 @@ func TestInfoAndTxsByHash(t *testing.T) { expectedTxs := types.Transactions{ &types.Transaction{}, } - oracle.blocks[hash] = expectedInfo - oracle.txs[hash] = expectedTxs + oracle.Blocks[hash] = expectedInfo + oracle.Txs[hash] = expectedTxs info, txs, err := client.InfoAndTxsByHash(context.Background(), hash) require.NoError(t, err) @@ -119,7 +120,7 @@ func TestL1BlockRefByNumber(t *testing.T) { t.Run("ParentOfHead", func(t *testing.T) { client, oracle := newClient(t) parent := blockNum(head.NumberU64() - 1) - oracle.blocks[parent.Hash()] = parent + oracle.Blocks[parent.Hash()] = parent ref, err := client.L1BlockRefByNumber(context.Background(), parent.NumberU64()) require.NoError(t, err) @@ -131,7 +132,7 @@ func TestL1BlockRefByNumber(t *testing.T) { blocks := []eth.BlockInfo{block} for i := 0; i < 10; i++ { block = blockNum(block.NumberU64() - 1) - oracle.blocks[block.Hash()] = block + oracle.Blocks[block.Hash()] = block blocks = append(blocks, block) } @@ -143,9 +144,9 @@ func TestL1BlockRefByNumber(t *testing.T) { }) } -func newClient(t *testing.T) (*OracleL1Client, *stubOracle) { - stub := newStubOracle(t) - stub.blocks[head.Hash()] = head +func newClient(t *testing.T) (*OracleL1Client, *test.StubOracle) { + stub := test.NewStubOracle(t) + stub.Blocks[head.Hash()] = head client := NewOracleL1Client(testlog.Logger(t, log.LvlDebug), stub, head.Hash()) return client, stub } diff --git a/op-program/client/l1/stub_oracle_test.go b/op-program/client/l1/stub_oracle_test.go deleted file mode 100644 index 4e87d4c13d345..0000000000000 --- a/op-program/client/l1/stub_oracle_test.go +++ /dev/null @@ -1,54 +0,0 @@ -package l1 - -import ( - "testing" - - "github.com/ethereum-optimism/optimism/op-node/eth" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" -) - -type stubOracle struct { - t *testing.T - - // blocks maps block hash to eth.BlockInfo - blocks map[common.Hash]eth.BlockInfo - - // txs maps block hash to transactions - txs map[common.Hash]types.Transactions - - // rcpts maps Block hash to receipts - rcpts map[common.Hash]types.Receipts -} - -func newStubOracle(t *testing.T) *stubOracle { - return &stubOracle{ - t: t, - blocks: make(map[common.Hash]eth.BlockInfo), - txs: make(map[common.Hash]types.Transactions), - rcpts: make(map[common.Hash]types.Receipts), - } -} -func (o stubOracle) HeaderByBlockHash(blockHash common.Hash) eth.BlockInfo { - info, ok := o.blocks[blockHash] - if !ok { - o.t.Fatalf("unknown block %s", blockHash) - } - return info -} - -func (o stubOracle) TransactionsByBlockHash(blockHash common.Hash) (eth.BlockInfo, types.Transactions) { - txs, ok := o.txs[blockHash] - if !ok { - o.t.Fatalf("unknown txs %s", blockHash) - } - return o.HeaderByBlockHash(blockHash), txs -} - -func (o stubOracle) ReceiptsByBlockHash(blockHash common.Hash) (eth.BlockInfo, types.Receipts) { - rcpts, ok := o.rcpts[blockHash] - if !ok { - o.t.Fatalf("unknown rcpts %s", blockHash) - } - return o.HeaderByBlockHash(blockHash), rcpts -} diff --git a/op-program/client/l1/test/stub_oracle.go b/op-program/client/l1/test/stub_oracle.go new file mode 100644 index 0000000000000..1ec03d945bc69 --- /dev/null +++ b/op-program/client/l1/test/stub_oracle.go @@ -0,0 +1,54 @@ +package test + +import ( + "testing" + + "github.com/ethereum-optimism/optimism/op-node/eth" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" +) + +type StubOracle struct { + t *testing.T + + // Blocks maps block hash to eth.BlockInfo + Blocks map[common.Hash]eth.BlockInfo + + // Txs maps block hash to transactions + Txs map[common.Hash]types.Transactions + + // Rcpts maps Block hash to receipts + Rcpts map[common.Hash]types.Receipts +} + +func NewStubOracle(t *testing.T) *StubOracle { + return &StubOracle{ + t: t, + Blocks: make(map[common.Hash]eth.BlockInfo), + Txs: make(map[common.Hash]types.Transactions), + Rcpts: make(map[common.Hash]types.Receipts), + } +} +func (o StubOracle) HeaderByBlockHash(blockHash common.Hash) eth.BlockInfo { + info, ok := o.Blocks[blockHash] + if !ok { + o.t.Fatalf("unknown block %s", blockHash) + } + return info +} + +func (o StubOracle) TransactionsByBlockHash(blockHash common.Hash) (eth.BlockInfo, types.Transactions) { + txs, ok := o.Txs[blockHash] + if !ok { + o.t.Fatalf("unknown txs %s", blockHash) + } + return o.HeaderByBlockHash(blockHash), txs +} + +func (o StubOracle) ReceiptsByBlockHash(blockHash common.Hash) (eth.BlockInfo, types.Receipts) { + rcpts, ok := o.Rcpts[blockHash] + if !ok { + o.t.Fatalf("unknown rcpts %s", blockHash) + } + return o.HeaderByBlockHash(blockHash), rcpts +} diff --git a/op-program/client/l2/cache_test.go b/op-program/client/l2/cache_test.go index b7445de20a29a..0dcf5a28dec2d 100644 --- a/op-program/client/l2/cache_test.go +++ b/op-program/client/l2/cache_test.go @@ -5,6 +5,7 @@ import ( "testing" "github.com/ethereum-optimism/optimism/op-node/testutils" + "github.com/ethereum-optimism/optimism/op-program/client/l2/test" "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/require" ) @@ -13,55 +14,55 @@ import ( var _ Oracle = (*CachingOracle)(nil) func TestBlockByHash(t *testing.T) { - stub, _ := newStubOracle(t) + stub, _ := test.NewStubOracle(t) oracle := NewCachingOracle(stub) rng := rand.New(rand.NewSource(1)) block, _ := testutils.RandomBlock(rng, 1) // Initial call retrieves from the stub - stub.blocks[block.Hash()] = block + stub.Blocks[block.Hash()] = block actual := oracle.BlockByHash(block.Hash()) require.Equal(t, block, actual) // Later calls should retrieve from cache - delete(stub.blocks, block.Hash()) + delete(stub.Blocks, block.Hash()) actual = oracle.BlockByHash(block.Hash()) require.Equal(t, block, actual) } func TestNodeByHash(t *testing.T) { - stub, stateStub := newStubOracle(t) + stub, stateStub := test.NewStubOracle(t) oracle := NewCachingOracle(stub) node := []byte{12, 3, 4} hash := common.Hash{0xaa} // Initial call retrieves from the stub - stateStub.data[hash] = node + stateStub.Data[hash] = node actual := oracle.NodeByHash(hash) require.Equal(t, node, actual) // Later calls should retrieve from cache - delete(stateStub.data, hash) + delete(stateStub.Data, hash) actual = oracle.NodeByHash(hash) require.Equal(t, node, actual) } func TestCodeByHash(t *testing.T) { - stub, stateStub := newStubOracle(t) + stub, stateStub := test.NewStubOracle(t) oracle := NewCachingOracle(stub) node := []byte{12, 3, 4} hash := common.Hash{0xaa} // Initial call retrieves from the stub - stateStub.code[hash] = node + stateStub.Code[hash] = node actual := oracle.CodeByHash(hash) require.Equal(t, node, actual) // Later calls should retrieve from cache - delete(stateStub.code, hash) + delete(stateStub.Code, hash) actual = oracle.CodeByHash(hash) require.Equal(t, node, actual) } diff --git a/op-program/client/l2/db_test.go b/op-program/client/l2/db_test.go index 0ed73207ae729..19671597f9d94 100644 --- a/op-program/client/l2/db_test.go +++ b/op-program/client/l2/db_test.go @@ -4,6 +4,7 @@ import ( "math/big" "testing" + "github.com/ethereum-optimism/optimism/op-program/client/l2/test" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/rawdb" @@ -27,7 +28,7 @@ var _ ethdb.KeyValueStore = (*OracleKeyValueStore)(nil) func TestGet(t *testing.T) { t.Run("IncorrectLengthKey", func(t *testing.T) { - oracle := newStubStateOracle(t) + oracle := test.NewStubStateOracle(t) db := NewOracleBackedDB(oracle) val, err := db.Get([]byte{1, 2, 3}) require.ErrorIs(t, err, ErrInvalidKeyLength) @@ -35,13 +36,13 @@ func TestGet(t *testing.T) { }) t.Run("KeyWithCodePrefix", func(t *testing.T) { - oracle := newStubStateOracle(t) + oracle := test.NewStubStateOracle(t) db := NewOracleBackedDB(oracle) key := common.HexToHash("0x12345678") prefixedKey := append(rawdb.CodePrefix, key.Bytes()...) expected := []byte{1, 2, 3} - oracle.code[key] = expected + oracle.Code[key] = expected val, err := db.Get(prefixedKey) require.NoError(t, err) @@ -49,13 +50,13 @@ func TestGet(t *testing.T) { }) t.Run("NormalKeyThatHappensToStartWithCodePrefix", func(t *testing.T) { - oracle := newStubStateOracle(t) + oracle := test.NewStubStateOracle(t) db := NewOracleBackedDB(oracle) key := make([]byte, common.HashLength) copy(rawdb.CodePrefix, key) println(key[0]) expected := []byte{1, 2, 3} - oracle.data[common.BytesToHash(key)] = expected + oracle.Data[common.BytesToHash(key)] = expected val, err := db.Get(key) require.NoError(t, err) @@ -65,8 +66,8 @@ func TestGet(t *testing.T) { t.Run("KnownKey", func(t *testing.T) { key := common.HexToHash("0xAA4488") expected := []byte{2, 6, 3, 8} - oracle := newStubStateOracle(t) - oracle.data[key] = expected + oracle := test.NewStubStateOracle(t) + oracle.Data[key] = expected db := NewOracleBackedDB(oracle) val, err := db.Get(key.Bytes()) require.NoError(t, err) @@ -76,7 +77,7 @@ func TestGet(t *testing.T) { func TestPut(t *testing.T) { t.Run("NewKey", func(t *testing.T) { - oracle := newStubStateOracle(t) + oracle := test.NewStubStateOracle(t) db := NewOracleBackedDB(oracle) key := common.HexToHash("0xAA4488") value := []byte{2, 6, 3, 8} @@ -88,7 +89,7 @@ func TestPut(t *testing.T) { require.Equal(t, value, actual) }) t.Run("ReplaceKey", func(t *testing.T) { - oracle := newStubStateOracle(t) + oracle := test.NewStubStateOracle(t) db := NewOracleBackedDB(oracle) key := common.HexToHash("0xAA4488") value1 := []byte{2, 6, 3, 8} @@ -109,16 +110,13 @@ func TestSupportsStateDBOperations(t *testing.T) { realDb := rawdb.NewDatabase(memorydb.New()) genesisBlock := l2Genesis.MustCommit(realDb) - loader := &kvStateOracle{ - t: t, - source: realDb, - } + loader := test.NewKvStateOracle(t, realDb) assertStateDataAvailable(t, NewOracleBackedDB(loader), l2Genesis, genesisBlock) } func TestUpdateState(t *testing.T) { l2Genesis := createGenesis() - oracle := newStubStateOracle(t) + oracle := test.NewStubStateOracle(t) db := rawdb.NewDatabase(NewOracleBackedDB(oracle)) genesisBlock := l2Genesis.MustCommit(db) diff --git a/op-program/client/l2/engine_backend_test.go b/op-program/client/l2/engine_backend_test.go index 705ac977f8cca..516948950e14f 100644 --- a/op-program/client/l2/engine_backend_test.go +++ b/op-program/client/l2/engine_backend_test.go @@ -8,6 +8,7 @@ import ( "github.com/ethereum-optimism/optimism/op-node/testlog" "github.com/ethereum-optimism/optimism/op-program/client/l2/engineapi" "github.com/ethereum-optimism/optimism/op-program/client/l2/engineapi/test" + l2test "github.com/ethereum-optimism/optimism/op-program/client/l2/test" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/consensus/beacon" @@ -143,7 +144,7 @@ func setupOracleBackedChainWithLowerHead(t *testing.T, blockCount int, headBlock return blocks, chain } -func setupOracle(t *testing.T, blockCount int, headBlockNumber int) (*params.ChainConfig, []*types.Block, *stubBlockOracle) { +func setupOracle(t *testing.T, blockCount int, headBlockNumber int) (*params.ChainConfig, []*types.Block, *l2test.StubBlockOracle) { deployConfig := &genesis.DeployConfig{ L1ChainID: 900, L2ChainID: 901, @@ -171,7 +172,7 @@ func setupOracle(t *testing.T, blockCount int, headBlockNumber int) (*params.Cha genesisBlock := l2Genesis.MustCommit(db) blocks, _ := core.GenerateChain(chainCfg, genesisBlock, consensus, db, blockCount, func(i int, gen *core.BlockGen) {}) blocks = append([]*types.Block{genesisBlock}, blocks...) - oracle := newStubOracleWithBlocks(t, blocks[:headBlockNumber+1], db) + oracle := l2test.NewStubOracleWithBlocks(t, blocks[:headBlockNumber+1], db) return chainCfg, blocks, oracle } diff --git a/op-program/client/l2/stub_oracle_test.go b/op-program/client/l2/stub_oracle_test.go deleted file mode 100644 index 177618290edca..0000000000000 --- a/op-program/client/l2/stub_oracle_test.go +++ /dev/null @@ -1,94 +0,0 @@ -package l2 - -import ( - "testing" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/rawdb" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/ethdb" -) - -type stubBlockOracle struct { - t *testing.T - blocks map[common.Hash]*types.Block - StateOracle -} - -func newStubOracle(t *testing.T) (*stubBlockOracle, *stubStateOracle) { - stateOracle := newStubStateOracle(t) - blockOracle := stubBlockOracle{ - t: t, - blocks: make(map[common.Hash]*types.Block), - StateOracle: stateOracle, - } - return &blockOracle, stateOracle -} - -func newStubOracleWithBlocks(t *testing.T, chain []*types.Block, db ethdb.Database) *stubBlockOracle { - blocks := make(map[common.Hash]*types.Block, len(chain)) - for _, block := range chain { - blocks[block.Hash()] = block - } - return &stubBlockOracle{ - blocks: blocks, - StateOracle: &kvStateOracle{t: t, source: db}, - } -} - -func (o stubBlockOracle) BlockByHash(blockHash common.Hash) *types.Block { - block, ok := o.blocks[blockHash] - if !ok { - o.t.Fatalf("requested unknown block %s", blockHash) - } - return block -} - -// kvStateOracle loads data from a source ethdb.KeyValueStore -type kvStateOracle struct { - t *testing.T - source ethdb.KeyValueStore -} - -func (o *kvStateOracle) NodeByHash(nodeHash common.Hash) []byte { - val, err := o.source.Get(nodeHash.Bytes()) - if err != nil { - o.t.Fatalf("error retrieving node %v: %v", nodeHash, err) - } - return val -} - -func (o *kvStateOracle) CodeByHash(hash common.Hash) []byte { - return rawdb.ReadCode(o.source, hash) -} - -func newStubStateOracle(t *testing.T) *stubStateOracle { - return &stubStateOracle{ - t: t, - data: make(map[common.Hash][]byte), - code: make(map[common.Hash][]byte), - } -} - -// Stub StateOracle implementation that reads from simple maps -type stubStateOracle struct { - t *testing.T - data map[common.Hash][]byte - code map[common.Hash][]byte -} - -func (o *stubStateOracle) NodeByHash(nodeHash common.Hash) []byte { - data, ok := o.data[nodeHash] - if !ok { - o.t.Fatalf("no value for node %v", nodeHash) - } - return data -} - -func (o *stubStateOracle) CodeByHash(hash common.Hash) []byte { - data, ok := o.code[hash] - if !ok { - o.t.Fatalf("no value for code %v", hash) - } - return data -} diff --git a/op-program/client/l2/test/stub_oracle.go b/op-program/client/l2/test/stub_oracle.go new file mode 100644 index 0000000000000..7ead955cb4e0d --- /dev/null +++ b/op-program/client/l2/test/stub_oracle.go @@ -0,0 +1,107 @@ +package test + +import ( + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/ethdb" +) + +// Same as l2.StateOracle but need to use our own copy to avoid dependency loops +type stateOracle interface { + NodeByHash(nodeHash common.Hash) []byte + CodeByHash(codeHash common.Hash) []byte +} + +type StubBlockOracle struct { + t *testing.T + Blocks map[common.Hash]*types.Block + stateOracle +} + +func NewStubOracle(t *testing.T) (*StubBlockOracle, *StubStateOracle) { + stateOracle := NewStubStateOracle(t) + blockOracle := StubBlockOracle{ + t: t, + Blocks: make(map[common.Hash]*types.Block), + stateOracle: stateOracle, + } + return &blockOracle, stateOracle +} + +func NewStubOracleWithBlocks(t *testing.T, chain []*types.Block, db ethdb.Database) *StubBlockOracle { + blocks := make(map[common.Hash]*types.Block, len(chain)) + for _, block := range chain { + blocks[block.Hash()] = block + } + return &StubBlockOracle{ + Blocks: blocks, + stateOracle: &KvStateOracle{t: t, Source: db}, + } +} + +func (o StubBlockOracle) BlockByHash(blockHash common.Hash) *types.Block { + block, ok := o.Blocks[blockHash] + if !ok { + o.t.Fatalf("requested unknown block %s", blockHash) + } + return block +} + +// KvStateOracle loads data from a source ethdb.KeyValueStore +type KvStateOracle struct { + t *testing.T + Source ethdb.KeyValueStore +} + +func NewKvStateOracle(t *testing.T, db ethdb.KeyValueStore) *KvStateOracle { + return &KvStateOracle{ + t: t, + Source: db, + } +} + +func (o *KvStateOracle) NodeByHash(nodeHash common.Hash) []byte { + val, err := o.Source.Get(nodeHash.Bytes()) + if err != nil { + o.t.Fatalf("error retrieving node %v: %v", nodeHash, err) + } + return val +} + +func (o *KvStateOracle) CodeByHash(hash common.Hash) []byte { + return rawdb.ReadCode(o.Source, hash) +} + +func NewStubStateOracle(t *testing.T) *StubStateOracle { + return &StubStateOracle{ + t: t, + Data: make(map[common.Hash][]byte), + Code: make(map[common.Hash][]byte), + } +} + +// StubStateOracle is a StateOracle implementation that reads from simple maps +type StubStateOracle struct { + t *testing.T + Data map[common.Hash][]byte + Code map[common.Hash][]byte +} + +func (o *StubStateOracle) NodeByHash(nodeHash common.Hash) []byte { + data, ok := o.Data[nodeHash] + if !ok { + o.t.Fatalf("no value for node %v", nodeHash) + } + return data +} + +func (o *StubStateOracle) CodeByHash(hash common.Hash) []byte { + data, ok := o.Code[hash] + if !ok { + o.t.Fatalf("no value for code %v", hash) + } + return data +}