ipld-eth-state-snapshot/pkg/snapshot/in_place_snapshot_test.go

190 lines
7.0 KiB
Go

// Copyright © 2022 Vulcanize, Inc
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package snapshot
import (
"context"
"strconv"
"testing"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/statediff/indexer/database/sql"
"github.com/ethereum/go-ethereum/statediff/indexer/database/sql/postgres"
"github.com/ethereum/go-ethereum/statediff/indexer/ipld"
"github.com/ethereum/go-ethereum/statediff/indexer/models"
"github.com/multiformats/go-multihash"
fixt "github.com/vulcanize/ipld-eth-state-snapshot/fixture"
"github.com/vulcanize/ipld-eth-state-snapshot/pkg/snapshot/pg"
snapt "github.com/vulcanize/ipld-eth-state-snapshot/pkg/types"
"github.com/vulcanize/ipld-eth-state-snapshot/test"
)
var (
pgConfig = test.DefaultPgConfig
nodeInfo = test.DefaultNodeInfo
snapshotHeight = 5
allTables = []*snapt.Table{
&snapt.TableIPLDBlock,
&snapt.TableNodeInfo,
&snapt.TableHeader,
&snapt.TableStateNode,
&snapt.TableStorageNode,
}
pgQueryStateCids = `SELECT cast(state_cids.block_number AS TEXT), state_cids.cid, state_cids.state_leaf_key, state_cids.node_type, state_cids.state_path, state_cids.header_id, state_cids.mh_key
FROM eth.state_cids
WHERE eth.state_cids.block_number = $1
ORDER BY state_cids.state_path`
pgQueryStorageCids = `SELECT cast(storage_cids.block_number AS TEXT), storage_cids.cid, storage_cids.state_path, storage_cids.storage_leaf_key, storage_cids.node_type, storage_cids.storage_path, storage_cids.mh_key, storage_cids.header_id
FROM eth.storage_cids
WHERE eth.storage_cids.block_number = $1
ORDER BY storage_cids.state_path, storage_cids.storage_path`
pgIpfsGet = `SELECT data FROM public.blocks
WHERE key = $1 AND block_number = $2`
)
func TestCreateInPlaceSnapshot(t *testing.T) {
test.NeedsDB(t)
ctx := context.Background()
driver, err := postgres.NewSQLXDriver(ctx, pgConfig, nodeInfo)
test.NoError(t, err)
db := postgres.NewPostgresDB(driver)
config := &Config{
Eth: &EthConfig{
NodeInfo: test.DefaultNodeInfo,
},
DB: &DBConfig{
URI: pgConfig.DbConnectionString(),
ConnConfig: pgConfig,
},
}
t.Run("Snapshot for blocks with contract deployment and transaction", func(t *testing.T) {
sql.TearDownDB(t, db)
_ = writeData(t, db, 4)
params := InPlaceSnapshotParams{StartHeight: uint64(0), EndHeight: uint64(snapshotHeight)}
err = CreateInPlaceSnapshot(config, params)
test.NoError(t, err)
// Check inplace snapshot was created for state_cids
compareStateNodes(t, db, fixt.ExpectedStateNodes)
// Check inplace snapshot was created for storage_cids
compareStorageNodes(t, db, fixt.ExpectedStorageNodes)
})
t.Run("Snapshot for blocks with contract deployment and transaction", func(t *testing.T) {
t.Skip("Fix in-place snapshot function for removed type nodes")
sql.TearDownDB(t, db)
_ = writeData(t, db, 5)
params := InPlaceSnapshotParams{StartHeight: uint64(0), EndHeight: uint64(snapshotHeight)}
err = CreateInPlaceSnapshot(config, params)
test.NoError(t, err)
// Check inplace snapshot was created for state_cids
compareStateNodes(t, db, fixt.ExpectedStateNodesAfterContractDestruction)
// Check inplace snapshot was created for storage_cids
compareStorageNodes(t, db, fixt.ExpectedStorageNodesAfterContractDestruction)
})
}
func writeData(t *testing.T, db *postgres.DB, height int) snapt.Publisher {
pub := pg.NewPublisher(db)
tx, err := pub.BeginTx()
test.NoError(t, err)
for _, block := range fixt.InPlaceSnapshotBlocks[:height] {
headerID := block.Hash.String()
for _, stateNode := range block.StateNodes {
test.NoError(t, pub.PublishStateNode(&stateNode, headerID, block.Number, tx))
}
for index, stateStorageNodes := range block.StorageNodes {
stateNode := block.StateNodes[index]
for _, storageNode := range stateStorageNodes {
test.NoError(t, pub.PublishStorageNode(&storageNode, headerID, block.Number, stateNode.Path, tx))
}
}
}
test.NoError(t, tx.Commit())
test.NoError(t, pub.PublishHeader(&fixt.Block5_Header))
return pub
}
func compareStateNodes(t *testing.T, db *postgres.DB, expectedStateNodes []snapt.Node) {
ctx := context.Background()
stateNodes := make([]models.StateNodeModel, 0)
err := db.Select(ctx, &stateNodes, pgQueryStateCids, snapshotHeight)
test.NoError(t, err)
test.ExpectEqual(t, len(expectedStateNodes), len(stateNodes))
for index, stateNode := range stateNodes {
var data []byte
err = db.Get(ctx, &data, pgIpfsGet, stateNode.MhKey, snapshotHeight)
test.NoError(t, err)
expectedStateNode := expectedStateNodes[index]
expectedCID, _ := ipld.RawdataToCid(ipld.MEthStateTrie, expectedStateNode.Value, multihash.KECCAK_256)
test.ExpectEqual(t, strconv.Itoa(snapshotHeight), stateNode.BlockNumber)
test.ExpectEqual(t, fixt.Block5_Header.Hash().String(), stateNode.HeaderID)
test.ExpectEqual(t, expectedCID.String(), stateNode.CID)
test.ExpectEqual(t, int(expectedStateNode.NodeType), stateNode.NodeType)
test.ExpectEqual(t, expectedStateNode.Key, common.HexToHash(stateNode.StateKey))
test.ExpectEqual(t, false, stateNode.Diff)
test.ExpectEqualBytes(t, expectedStateNode.Path, stateNode.Path)
test.ExpectEqualBytes(t, expectedStateNode.Value, data)
}
}
func compareStorageNodes(t *testing.T, db *postgres.DB, expectedStorageNodes []fixt.StorageNodeWithState) {
ctx := context.Background()
storageNodes := make([]models.StorageNodeModel, 0)
err := db.Select(ctx, &storageNodes, pgQueryStorageCids, snapshotHeight)
test.NoError(t, err)
test.ExpectEqual(t, len(expectedStorageNodes), len(storageNodes))
for index, storageNode := range storageNodes {
expectedStorageNode := expectedStorageNodes[index]
expectedStorageCID, _ := ipld.RawdataToCid(ipld.MEthStorageTrie, expectedStorageNode.Value, multihash.KECCAK_256)
test.ExpectEqual(t, strconv.Itoa(snapshotHeight), storageNode.BlockNumber)
test.ExpectEqual(t, fixt.Block5_Header.Hash().String(), storageNode.HeaderID)
test.ExpectEqual(t, expectedStorageCID.String(), storageNode.CID)
test.ExpectEqual(t, int(expectedStorageNode.NodeType), storageNode.NodeType)
test.ExpectEqual(t, expectedStorageNode.Key, common.HexToHash(storageNode.StorageKey))
test.ExpectEqual(t, expectedStorageNode.StatePath, storageNode.StatePath)
test.ExpectEqual(t, expectedStorageNode.Path, storageNode.Path)
test.ExpectEqual(t, false, storageNode.Diff)
var data []byte
err = db.Get(ctx, &data, pgIpfsGet, storageNode.MhKey, snapshotHeight)
test.NoError(t, err)
test.ExpectEqualBytes(t, expectedStorageNode.Value, data)
}
}