diff --git a/pkg/eth/api_test.go b/pkg/eth/api_test.go index 91d80b1d..feb500bf 100644 --- a/pkg/eth/api_test.go +++ b/pkg/eth/api_test.go @@ -1145,8 +1145,4 @@ var _ = Describe("API", func() { Expect(code).To(BeEmpty()) }) }) - - Describe("eth_getSlice", func() { - // TODO Implement - }) }) diff --git a/pkg/eth/backend.go b/pkg/eth/backend.go index 152290a9..fa1f8fb7 100644 --- a/pkg/eth/backend.go +++ b/pkg/eth/backend.go @@ -109,9 +109,21 @@ const ( AND state_cids.state_path = state_accounts.state_path AND state_cids.header_id = state_accounts.header_id AND state_cids.block_number = state_accounts.block_number + AND state_cids.node_type != 3 AND state_accounts.header_id = (SELECT canonical_header_hash(state_accounts.block_number)) ORDER BY state_accounts.block_number DESC LIMIT 1` + RetrieveAccountByStateCID = `SELECT state_leaf_key, storage_root, code_hash + FROM eth.state_cids + INNER JOIN eth.state_accounts ON ( + state_cids.state_path = state_accounts.state_path + AND state_cids.header_id = state_accounts.header_id + AND state_cids.block_number = state_accounts.block_number + ) + WHERE state_cids.cid = $1 + AND state_cids.block_number <= $2 + ORDER BY state_cids.block_number DESC + LIMIT 1` ) const ( @@ -971,7 +983,24 @@ func (b *Backend) GetStateSlice(path string, depth int, root common.Hash) (*GetS leafNodes = append(leafNodes, stemLeafCIDs...) leafNodes = append(leafNodes, sliceLeafCIDs...) leafNodes = append(leafNodes, headLeafCID...) - // TODO: fill in contract data `response.Leaves` + + contractCount := 0 + for _, leafNodeCID := range leafNodes { + stateLeafKey, storageRoot, code, err := b.getAccountByStateCID(tx, leafNodeCID.String(), blockHeight) + if err != nil { + return nil, fmt.Errorf("GetStateSlice account lookup error: %s", err.Error()) + } + + response.Leaves[stateLeafKey] = GetSliceResponseAccount{ + StorageRoot: storageRoot, + EVMCode: common.Bytes2Hex(code), + } + + if len(code) > 0 { + contractCount++ + } + } + response.MetaData.TimeStats["03-fetch-leaves-info"] = strconv.Itoa(int(makeTimestamp() - leafFetchStart)) maxDepth := deepestPath - len(headPath) @@ -982,7 +1011,7 @@ func (b *Backend) GetStateSlice(path string, depth int, root common.Hash) (*GetS response.MetaData.NodeStats["02-total-trie-nodes"] = strconv.Itoa(len(response.TrieNodes.Stem) + len(response.TrieNodes.Head) + len(response.TrieNodes.Slice)) response.MetaData.NodeStats["03-leaves"] = strconv.Itoa(len(leafNodes)) - response.MetaData.NodeStats["04-smart-contracts"] = "" // TODO: count # of contracts + response.MetaData.NodeStats["04-smart-contracts"] = strconv.Itoa(contractCount) response.MetaData.NodeStats["00-stem-and-head-nodes"] = strconv.Itoa(len(response.TrieNodes.Stem) + len(response.TrieNodes.Head)) return response, nil @@ -1102,6 +1131,32 @@ func (b *Backend) getStateNodesByPathsAndBlockNumber(tx *sqlx.Tx, paths [][]byte return nodes, leafCIDs, deepestPath, strconv.Itoa(int(makeTimestamp() - fetchStart)), nil } +func (b *Backend) getAccountByStateCID(tx *sqlx.Tx, cid string, blockHeight uint64) (string, string, []byte, error) { + var err error + var res struct { + StateLeafKey string `db:"state_leaf_key"` + StorageRoot string `db:"storage_root"` + CodeHash []byte `db:"code_hash"` + } + + if err = tx.Get(&res, RetrieveAccountByStateCID, cid, blockHeight); err != nil { + return "", "", nil, err + } + + mhKey, err := ethServerShared.MultihashKeyFromKeccak256(common.BytesToHash(res.CodeHash)) + if err != nil { + return "", "", nil, err + } + + code := make([]byte, 0) + err = tx.Get(&code, RetrieveCodeByMhKey, mhKey) + if err != nil { + return "", "", nil, err + } + + return res.StateLeafKey, res.StorageRoot, code, nil +} + func (b *Backend) getStorageNodesByStateLeafKeyAndPathsAndBlockNumber(tx *sqlx.Tx, stateLeafKey string, paths [][]byte, blockHeight uint64) (map[string]string, []cid.Cid, int, string, error) { nodes := make(map[string]string) fetchStart := makeTimestamp() diff --git a/pkg/eth/types.go b/pkg/eth/types.go index 6849b9d3..d9631786 100644 --- a/pkg/eth/types.go +++ b/pkg/eth/types.go @@ -271,7 +271,7 @@ type GetSliceResponse struct { SliceID string `json:"sliceId"` MetaData GetSliceResponseMetadata `json:"metadata"` TrieNodes GetSliceResponseTrieNodes `json:"trieNodes"` - Leaves map[string]GetSliceResponseAccount `json:"leaves"` // we won't be using addresses, but keccak256(address) // TODO: address comment + Leaves map[string]GetSliceResponseAccount `json:"leaves"` // key: Keccak256Hash(address) in hex (leafKey) } func (sr *GetSliceResponse) init(path string, depth int, root common.Hash) { @@ -294,7 +294,7 @@ type GetSliceResponseMetadata struct { } type GetSliceResponseTrieNodes struct { - Stem map[string]string `json:"stem"` + Stem map[string]string `json:"stem"` // key: Keccak256Hash(data) in hex, value: trie node data in hex Head map[string]string `json:"head"` Slice map[string]string `json:"sliceNodes"` }