diff --git a/db/migrations/00014_create_stored_functions.sql b/db/migrations/00014_create_stored_functions.sql index 1e9ad468..f5457b8b 100644 --- a/db/migrations/00014_create_stored_functions.sql +++ b/db/migrations/00014_create_stored_functions.sql @@ -1,4 +1,20 @@ -- +goose Up + + +-- +goose StatementBegin +-- returns if a storage node at the provided path was removed in the range >= the provided height and <= the provided block hash +CREATE OR REPLACE FUNCTION was_state_leaf_removed(state_leaf_key BYTEA, block_num BIGINT) RETURNS BOOLEAN +AS $$ +SELECT exists(SELECT 1 + FROM eth.state_cids + INNER JOIN eth.header_cids ON (state_cids.header_id = header_cids.id) + WHERE state_leaf_key = state_leaf_key + AND block_number <= block_num + AND state_cids.node_type = 3 + LIMIT 1); +$$ LANGUAGE SQL; +-- +goose StatementEnd + -- +goose StatementBegin CREATE TYPE child_result AS ( has_child BOOLEAN, @@ -115,6 +131,7 @@ LANGUAGE 'plpgsql'; -- +goose StatementEnd -- +goose Down +DROP FUNCTION was_state_leaf_removed; DROP FUNCTION canonical_header_id; DROP FUNCTION canonical_header_from_array; DROP FUNCTION has_child; diff --git a/docker-compose.yml b/docker-compose.yml index c24619bc..2ef02cfd 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -39,6 +39,7 @@ services: - vdb_db_eth_server:/var/lib/postgresql/data ports: - "127.0.0.1:8077:5432" + command: ["postgres", "-c", "log_statement=all"] eth-server: restart: unless-stopped diff --git a/pkg/eth/ipld_retriever.go b/pkg/eth/ipld_retriever.go index b28fb9dc..7c82e3ba 100644 --- a/pkg/eth/ipld_retriever.go +++ b/pkg/eth/ipld_retriever.go @@ -127,7 +127,7 @@ const ( AND block_number <= $2 ORDER BY block_number DESC LIMIT 1` - RetrieveStorageLeafByAddressHashAndLeafKeyAndBlockNumberPgStr = `SELECT storage_cids.cid, data, storage_cids.node_type + RetrieveStorageLeafByAddressHashAndLeafKeyAndBlockNumberPgStr = `SELECT storage_cids.cid, data, storage_cids.node_type, was_state_leaf_removed(state_leaf_key, block_number) AS state_leaf_removed FROM eth.storage_cids INNER JOIN eth.state_cids ON (storage_cids.state_id = state_cids.id) INNER JOIN eth.header_cids ON (state_cids.header_id = header_cids.id) @@ -137,7 +137,7 @@ const ( AND block_number <= $3 ORDER BY block_number DESC LIMIT 1` - RetrieveStorageLeafByAddressHashAndLeafKeyAndBlockHashPgStr = `SELECT storage_cids.cid, data, storage_cids.node_type + RetrieveStorageLeafByAddressHashAndLeafKeyAndBlockHashPgStr = `SELECT storage_cids.cid, data, storage_cids.node_type, was_state_leaf_removed(state_leaf_key, block_number) AS state_leaf_removed FROM eth.storage_cids INNER JOIN eth.state_cids ON (storage_cids.state_id = state_cids.id) INNER JOIN eth.header_cids ON (state_cids.header_id = header_cids.id) @@ -427,9 +427,10 @@ func (r *IPLDRetriever) RetrieveReceiptByHash(hash common.Hash) (string, []byte, } type nodeInfo struct { - CID string `db:"cid"` - Data []byte `db:"data"` - NodeType int `db:"node_type"` + CID string `db:"cid"` + Data []byte `db:"data"` + NodeType int `db:"node_type"` + StateLeafRemoved bool `db:"state_leaf_removed"` } // RetrieveAccountByAddressAndBlockHash returns the cid and rlp bytes for the account corresponding to the provided address and block hash @@ -486,7 +487,7 @@ func (r *IPLDRetriever) RetrieveStorageAtByAddressAndStorageSlotAndBlockHash(add if err := r.db.Get(storageResult, RetrieveStorageLeafByAddressHashAndLeafKeyAndBlockHashPgStr, stateLeafKey.Hex(), storageHash.Hex(), hash.Hex()); err != nil { return "", nil, nil, err } - if storageResult.NodeType == removedNode { + if storageResult.StateLeafRemoved || storageResult.NodeType == removedNode { return "", EmptyNodeValue, EmptyNodeValue, nil } var i []interface{} @@ -509,7 +510,7 @@ func (r *IPLDRetriever) RetrieveStorageAtByAddressAndStorageKeyAndBlockNumber(ad return "", nil, err } - if storageResult.NodeType == removedNode { + if storageResult.StateLeafRemoved || storageResult.NodeType == removedNode { return "", EmptyNodeValue, nil } var i []interface{} diff --git a/scripts/run_intregration_test.sh b/scripts/run_intregration_test.sh index f9056dc4..c81ca89b 100755 --- a/scripts/run_intregration_test.sh +++ b/scripts/run_intregration_test.sh @@ -5,9 +5,9 @@ set -o xtrace docker-compose down --remove-orphans --volumes # Build and start the containers. -# Note: Build only if `ipld-eth-server` code is modified. Otherwise comment this line. -docker build -t ipld-eth-server_eth-server:latest . -docker-compose -f docker-compose.test.yml -f docker-compose.yml up -d db dapptools contract eth-server +# Note: Build only if `ipld-eth-server` or other container code is modified. Otherwise comment this line. +docker-compose -f docker-compose.test.yml -f docker-compose.yml build eth-server +docker-compose -f docker-compose.test.yml -f docker-compose.yml up -d db dapptools contract eth-server 2>&1 | tee docker.logs export PGPASSWORD=password export DATABASE_USER=vdbm diff --git a/test/contract/src/index.js b/test/contract/src/index.js index 6339a1d9..e484d769 100644 --- a/test/contract/src/index.js +++ b/test/contract/src/index.js @@ -15,6 +15,8 @@ fastify.get('/v1/deployContract', async (req, reply) => { const token = await GLDToken.deploy(); await token.deployed(); + console.log(`Deployed block ${token.deployTransaction.blockNumber}`) + return { address: token.address, txHash: token.deployTransaction.hash, @@ -31,6 +33,8 @@ fastify.get('/v1/destroyContract', async (req, reply) => { await token.destroy(); const blockNum = await hre.ethers.provider.getBlockNumber() + console.log(`Destroyed block ${blockNum}`) + return { blockNumber: blockNum, } diff --git a/test/helper.go b/test/helper.go index c17f4283..1cc741d5 100644 --- a/test/helper.go +++ b/test/helper.go @@ -15,9 +15,7 @@ type ContractDeployed struct { } type ContractDestroyed struct { - TransactionHash string `json:"txHash"` - BlockNumber int64 `json:"blockNumber"` - BlockHash string `json:"blockHash"` + BlockNumber int64 `json:"blockNumber"` } type Tx struct { @@ -56,6 +54,7 @@ func DestroyContract(addr string) (*ContractDestroyed, error) { } defer res.Body.Close() + fmt.Println(res.Body) var data ContractDestroyed decoder := json.NewDecoder(res.Body) diff --git a/test/integration_test.go b/test/integration_test.go index 8e7a8c26..ca43dad9 100644 --- a/test/integration_test.go +++ b/test/integration_test.go @@ -2,6 +2,7 @@ package integration_test import ( "context" + "fmt" "math/big" "time" @@ -317,6 +318,8 @@ var _ = Describe("Integration test", func() { contract, contractErr = integration.DeployContract() erc20TotalSupply, bigIntResult = new(big.Int).SetString("1000000000000000000000", 10) + fmt.Printf("Deployed address: %d\n", contract.BlockNumber) + time.Sleep(sleepInterval) }) @@ -393,7 +396,7 @@ var _ = Describe("Integration test", func() { Expect(gethStorage).To(Equal(ipldStorage)) }) - It("get storage after self destruct", func() { + FIt("get storage after self destruct", func() { totalSupplyIndex := "0x2" tx, err := integration.DestroyContract(contract.Address) @@ -401,6 +404,10 @@ var _ = Describe("Integration test", func() { time.Sleep(sleepInterval) + fmt.Printf("Destroyed address: %d\n", tx.BlockNumber) + + fmt.Printf("Contract Address: %s \n", contract.Address) + gethStorage1, err := gethClient.StorageAt(ctx, common.HexToAddress(contract.Address), common.HexToHash(totalSupplyIndex), big.NewInt(tx.BlockNumber-1)) Expect(err).ToNot(HaveOccurred()) gethStorage2, err := gethClient.StorageAt(ctx, common.HexToAddress(contract.Address), common.HexToHash(totalSupplyIndex), big.NewInt(tx.BlockNumber)) @@ -416,6 +423,12 @@ var _ = Describe("Integration test", func() { Expect(ipldStorage1).To(Equal(gethStorage1)) Expect(ipldStorage2).To(Equal(gethStorage2)) + + // Query the current block + ipldStorage3, err := ipldClient.StorageAt(ctx, common.HexToAddress(contract.Address), common.HexToHash(totalSupplyIndex), nil) + Expect(err).ToNot(HaveOccurred()) + + Expect(ipldStorage2).To(Equal(ipldStorage3)) }) })