Update state JSON-RPC endpoints to directly lookup by blockNumber and skip lookup by blockHash. (#2623)

This commit is contained in:
web3-developer 2024-09-13 14:51:16 +08:00 committed by GitHub
parent 9c1594b417
commit b11701c75a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 79 additions and 87 deletions

View File

@ -266,50 +266,56 @@ proc getProofsByStateRoot*(
# Used by: eth_getBalance,
proc getBalance*(
n: StateNetwork, blockHash: BlockHash, address: EthAddress
n: StateNetwork, blockNumOrHash: uint64 | BlockHash, address: EthAddress
): Future[Opt[UInt256]] {.async: (raises: [CancelledError]).} =
let stateRoot = (await n.getStateRootByBlockHash(blockHash)).valueOr:
warn "Failed to get state root by block hash"
let stateRoot = (await n.getStateRootByBlockNumOrHash(blockNumOrHash)).valueOr:
warn "Failed to get state root by block number or hash", blockNumOrHash
return Opt.none(UInt256)
await n.getBalanceByStateRoot(stateRoot, address)
# Used by: eth_getTransactionCount
proc getTransactionCount*(
n: StateNetwork, blockHash: BlockHash, address: EthAddress
n: StateNetwork, blockNumOrHash: uint64 | BlockHash, address: EthAddress
): Future[Opt[AccountNonce]] {.async: (raises: [CancelledError]).} =
let stateRoot = (await n.getStateRootByBlockHash(blockHash)).valueOr:
warn "Failed to get state root by block hash"
let stateRoot = (await n.getStateRootByBlockNumOrHash(blockNumOrHash)).valueOr:
warn "Failed to get state root by block number or hash", blockNumOrHash
return Opt.none(AccountNonce)
await n.getTransactionCountByStateRoot(stateRoot, address)
# Used by: eth_getStorageAt
proc getStorageAt*(
n: StateNetwork, blockHash: BlockHash, address: EthAddress, slotKey: UInt256
n: StateNetwork,
blockNumOrHash: uint64 | BlockHash,
address: EthAddress,
slotKey: UInt256,
): Future[Opt[UInt256]] {.async: (raises: [CancelledError]).} =
let stateRoot = (await n.getStateRootByBlockHash(blockHash)).valueOr:
warn "Failed to get state root by block hash"
let stateRoot = (await n.getStateRootByBlockNumOrHash(blockNumOrHash)).valueOr:
warn "Failed to get state root by block number or hash", blockNumOrHash
return Opt.none(UInt256)
await n.getStorageAtByStateRoot(stateRoot, address, slotKey)
# Used by: eth_getCode
proc getCode*(
n: StateNetwork, blockHash: BlockHash, address: EthAddress
n: StateNetwork, blockNumOrHash: uint64 | BlockHash, address: EthAddress
): Future[Opt[Bytecode]] {.async: (raises: [CancelledError]).} =
let stateRoot = (await n.getStateRootByBlockHash(blockHash)).valueOr:
warn "Failed to get state root by block hash"
let stateRoot = (await n.getStateRootByBlockNumOrHash(blockNumOrHash)).valueOr:
warn "Failed to get state root by block number or hash", blockNumOrHash
return Opt.none(Bytecode)
await n.getCodeByStateRoot(stateRoot, address)
# Used by: eth_getProof
proc getProofs*(
n: StateNetwork, blockHash: BlockHash, address: EthAddress, slotKeys: seq[UInt256]
n: StateNetwork,
blockNumOrHash: uint64 | BlockHash,
address: EthAddress,
slotKeys: seq[UInt256],
): Future[Opt[Proofs]] {.async: (raises: [CancelledError]).} =
let stateRoot = (await n.getStateRootByBlockHash(blockHash)).valueOr:
warn "Failed to get state root by block hash"
let stateRoot = (await n.getStateRootByBlockNumOrHash(blockNumOrHash)).valueOr:
warn "Failed to get state root by block number or hash", blockNumOrHash
return Opt.none(Proofs)
await n.getProofsByStateRoot(stateRoot, address, slotKeys)

View File

@ -130,15 +130,15 @@ proc getContractCode*(
): Future[Opt[ContractCodeRetrieval]] {.async: (raw: true, raises: [CancelledError]).} =
n.getContent(key, ContractCodeRetrieval)
proc getStateRootByBlockHash*(
n: StateNetwork, hash: BlockHash
proc getStateRootByBlockNumOrHash*(
n: StateNetwork, blockNumOrHash: uint64 | BlockHash
): Future[Opt[KeccakHash]] {.async: (raises: [CancelledError]).} =
if n.historyNetwork.isNone():
warn "History network is not available"
return Opt.none(KeccakHash)
let header = (await n.historyNetwork.get().getVerifiedBlockHeader(hash)).valueOr:
warn "Failed to get block header by hash", hash
let header = (await n.historyNetwork.get().getVerifiedBlockHeader(blockNumOrHash)).valueOr:
warn "Failed to get block header from history", blockNumOrHash
return Opt.none(KeccakHash)
Opt.some(header.stateRoot)
@ -156,7 +156,7 @@ proc processOffer*(
let res =
if n.validateStateIsCanonical:
let stateRoot = (await n.getStateRootByBlockHash(contentValue.blockHash)).valueOr:
let stateRoot = (await n.getStateRootByBlockNumOrHash(contentValue.blockHash)).valueOr:
return err("Failed to get state root by block hash")
validateOffer(Opt.some(stateRoot), contentKey, contentValue)
else:

View File

@ -364,10 +364,7 @@ proc installEthApiHandlers*(
let
blockNumber = quantityTag.number.uint64
blockHash = (await historyNetwork.getBlockHashByNumber(blockNumber)).valueOr:
raise newException(ValueError, "Unable to get block hash")
balance = (await sn.getBalance(blockHash, data.EthAddress)).valueOr:
balance = (await sn.getBalance(blockNumber, data.EthAddress)).valueOr:
raise newException(ValueError, "Unable to get balance")
return balance
@ -390,10 +387,7 @@ proc installEthApiHandlers*(
let
blockNumber = quantityTag.number.uint64
blockHash = (await historyNetwork.getBlockHashByNumber(blockNumber)).valueOr:
raise newException(ValueError, "Unable to get block hash")
nonce = (await sn.getTransactionCount(blockHash, data.EthAddress)).valueOr:
nonce = (await sn.getTransactionCount(blockNumber, data.EthAddress)).valueOr:
raise newException(ValueError, "Unable to get transaction count")
return nonce.Quantity
@ -416,10 +410,7 @@ proc installEthApiHandlers*(
let
blockNumber = quantityTag.number.uint64
blockHash = (await historyNetwork.getBlockHashByNumber(blockNumber)).valueOr:
raise newException(ValueError, "Unable to get block hash")
slotValue = (await sn.getStorageAt(blockHash, data.EthAddress, slot)).valueOr:
slotValue = (await sn.getStorageAt(blockNumber, data.EthAddress, slot)).valueOr:
raise newException(ValueError, "Unable to get storage slot")
return FixedBytes[32](slotValue.toBytesBE())
@ -441,10 +432,7 @@ proc installEthApiHandlers*(
let
blockNumber = quantityTag.number.uint64
blockHash = (await historyNetwork.getBlockHashByNumber(blockNumber)).valueOr:
raise newException(ValueError, "Unable to get block hash")
bytecode = (await sn.getCode(blockHash, data.EthAddress)).valueOr:
bytecode = (await sn.getCode(blockNumber, data.EthAddress)).valueOr:
raise newException(ValueError, "Unable to get code")
return bytecode.asSeq()
@ -469,9 +457,7 @@ proc installEthApiHandlers*(
let
blockNumber = quantityTag.number.uint64
blockHash = (await historyNetwork.getBlockHashByNumber(blockNumber)).valueOr:
raise newException(ValueError, "Unable to get block hash")
proofs = (await sn.getProofs(blockHash, data.EthAddress, slots)).valueOr:
proofs = (await sn.getProofs(blockNumber, data.EthAddress, slots)).valueOr:
raise newException(ValueError, "Unable to get proofs")
var storageProof = newSeqOfCap[StorageProof](slots.len)

View File

@ -141,8 +141,8 @@ proc stop*(sn: StateNode) {.async.} =
proc containsId*(sn: StateNode, contentId: ContentId): bool {.inline.} =
return sn.stateNetwork.contentDB.get(contentId).isSome()
proc mockBlockHashToStateRoot*(
sn: StateNode, blockHash: BlockHash, stateRoot: KeccakHash
proc mockStateRootLookup*(
sn: StateNode, blockNumOrHash: uint64 | BlockHash, stateRoot: KeccakHash
) =
let
blockHeader = BlockHeader(stateRoot: stateRoot)
@ -150,7 +150,7 @@ proc mockBlockHashToStateRoot*(
blockHeaderWithProof = BlockHeaderWithProof(
header: ByteList[2048].init(headerRlp), proof: BlockHeaderProof.init()
)
contentKeyBytes = blockHeaderContentKey(blockHash).encode()
contentKeyBytes = blockHeaderContentKey(blockNumOrHash).encode()
contentId = history_content.toContentId(contentKeyBytes)
sn.portalProtocol().storeContent(

View File

@ -132,19 +132,19 @@ suite "State Endpoints - Genesis JSON Files":
let
accounts = getGenesisAlloc("fluffy" / "tests" / "custom_genesis" / file)
(accountState, storageStates) = accounts.toState()
blockHash = keccakHash("blockHash") # use a dummy block hash
blockNumber = 123.uint64 # use a dummy block number
# mock the block hash because we don't have history network running
stateNode.mockBlockHashToStateRoot(blockHash, accountState.rootHash())
stateNode.mockStateRootLookup(blockNumber, accountState.rootHash())
for address, account in accounts:
stateNode.setupAccountInDb(accountState, address)
# get balance and nonce of existing account
let
balanceRes = await stateNode.stateNetwork.getBalance(blockHash, address)
balanceRes = await stateNode.stateNetwork.getBalance(blockNumber, address)
nonceRes =
await stateNode.stateNetwork.getTransactionCount(blockHash, address)
await stateNode.stateNetwork.getTransactionCount(blockNumber, address)
check:
balanceRes.get() == account.balance
nonceRes.get() == account.nonce
@ -153,7 +153,7 @@ suite "State Endpoints - Genesis JSON Files":
stateNode.setupCodeInDb(address, account.code)
# get code of existing account
let codeRes = await stateNode.stateNetwork.getCode(blockHash, address)
let codeRes = await stateNode.stateNetwork.getCode(blockNumber, address)
check:
codeRes.get().asSeq() == account.code
@ -163,17 +163,17 @@ suite "State Endpoints - Genesis JSON Files":
# get storage slots of existing account
let slotRes =
await stateNode.stateNetwork.getStorageAt(blockHash, address, slotKey)
await stateNode.stateNetwork.getStorageAt(blockNumber, address, slotKey)
check:
slotRes.get() == slotValue
else:
# account exists but code and slot doesn't exist
let
codeRes = await stateNode.stateNetwork.getCode(blockHash, address)
codeRes = await stateNode.stateNetwork.getCode(blockNumber, address)
slotRes0 =
await stateNode.stateNetwork.getStorageAt(blockHash, address, 0.u256)
await stateNode.stateNetwork.getStorageAt(blockNumber, address, 0.u256)
slotRes1 =
await stateNode.stateNetwork.getStorageAt(blockHash, address, 1.u256)
await stateNode.stateNetwork.getStorageAt(blockNumber, address, 1.u256)
check:
codeRes.get().asSeq().len() == 0
slotRes0.get() == 0.u256
@ -185,12 +185,12 @@ suite "State Endpoints - Genesis JSON Files":
EthAddress.fromHex("0xBAD0000000000000000000000000000000000000")
let
balanceRes = await stateNode.stateNetwork.getBalance(blockHash, badAddress)
balanceRes = await stateNode.stateNetwork.getBalance(blockNumber, badAddress)
nonceRes =
await stateNode.stateNetwork.getTransactionCount(blockHash, badAddress)
codeRes = await stateNode.stateNetwork.getCode(blockHash, badAddress)
await stateNode.stateNetwork.getTransactionCount(blockNumber, badAddress)
codeRes = await stateNode.stateNetwork.getCode(blockNumber, badAddress)
slotRes =
await stateNode.stateNetwork.getStorageAt(blockHash, badAddress, 0.u256)
await stateNode.stateNetwork.getStorageAt(blockNumber, badAddress, 0.u256)
check:
balanceRes.get() == 0.u256
@ -209,10 +209,10 @@ suite "State Endpoints - Genesis JSON Files":
let
accounts = getGenesisAlloc("fluffy" / "tests" / "custom_genesis" / file)
(accountState, storageStates) = accounts.toState()
blockHash = keccakHash("blockHash") # use a dummy block hash
blockNumber = 123.uint64 # use a dummy block number
# mock the block hash because we don't have history network running
stateNode.mockBlockHashToStateRoot(blockHash, accountState.rootHash())
stateNode.mockStateRootLookup(blockNumber, accountState.rootHash())
for address, account in accounts:
stateNode.setupAccountInDb(accountState, address)
@ -226,7 +226,7 @@ suite "State Endpoints - Genesis JSON Files":
let
slotKeys = newSeq[UInt256]()
proofs = (
await stateNode.stateNetwork.getProofs(blockHash, address, slotKeys)
await stateNode.stateNetwork.getProofs(blockNumber, address, slotKeys)
).valueOr:
raiseAssert("Failed to get proofs")
check:
@ -246,7 +246,7 @@ suite "State Endpoints - Genesis JSON Files":
let
slotKeys = @[slotKey]
proofs = (
await stateNode.stateNetwork.getProofs(blockHash, address, slotKeys)
await stateNode.stateNetwork.getProofs(blockNumber, address, slotKeys)
).valueOr:
raiseAssert("Failed to get proofs")
check:
@ -265,7 +265,7 @@ suite "State Endpoints - Genesis JSON Files":
let
slotKeys = @[2.u256]
proofs = (
await stateNode.stateNetwork.getProofs(blockHash, address, slotKeys)
await stateNode.stateNetwork.getProofs(blockNumber, address, slotKeys)
).valueOr:
raiseAssert("Failed to get proofs")
check:
@ -285,7 +285,7 @@ suite "State Endpoints - Genesis JSON Files":
badAddress = EthAddress.fromHex("0xBAD0000000000000000000000000000000000000")
slotKeys = @[0.u256, 1.u256]
proofs = (
await stateNode.stateNetwork.getProofs(blockHash, badAddress, slotKeys)
await stateNode.stateNetwork.getProofs(blockNumber, badAddress, slotKeys)
).valueOr:
raiseAssert("Failed to get proofs")
check:

View File

@ -58,8 +58,8 @@ procSuite "State Endpoints":
contentValue = AccountTrieNodeOffer.decode(contentValueBytes).get()
# set valid state root
stateNode1.mockBlockHashToStateRoot(contentValue.blockHash, stateRoot)
stateNode2.mockBlockHashToStateRoot(contentValue.blockHash, stateRoot)
stateNode1.mockStateRootLookup(contentValue.blockHash, stateRoot)
stateNode2.mockStateRootLookup(contentValue.blockHash, stateRoot)
# offer the leaf node
let rootKeyBytes = await stateNode1.portalProtocol.recursiveGossipOffer(
@ -181,8 +181,8 @@ procSuite "State Endpoints":
contentValue = AccountTrieNodeOffer.decode(contentValueBytes).get()
# set valid state root
stateNode1.mockBlockHashToStateRoot(contentValue.blockHash, stateRoot)
stateNode2.mockBlockHashToStateRoot(contentValue.blockHash, stateRoot)
stateNode1.mockStateRootLookup(contentValue.blockHash, stateRoot)
stateNode2.mockStateRootLookup(contentValue.blockHash, stateRoot)
# offer the leaf node
let rootKeyBytes = await stateNode1.portalProtocol.recursiveGossipOffer(
@ -209,8 +209,8 @@ procSuite "State Endpoints":
contentValue = ContractTrieNodeOffer.decode(contentValueBytes).get()
# set valid state root
stateNode1.mockBlockHashToStateRoot(contentValue.blockHash, stateRoot)
stateNode2.mockBlockHashToStateRoot(contentValue.blockHash, stateRoot)
stateNode1.mockStateRootLookup(contentValue.blockHash, stateRoot)
stateNode2.mockStateRootLookup(contentValue.blockHash, stateRoot)
# offer the leaf node
let storageRootKeyBytes = await stateNode1.portalProtocol.recursiveGossipOffer(
@ -262,8 +262,8 @@ procSuite "State Endpoints":
contentValue = ContractCodeOffer.decode(contentValueBytes).get()
# set valid state root
stateNode1.mockBlockHashToStateRoot(contentValue.blockHash, stateRoot)
stateNode2.mockBlockHashToStateRoot(contentValue.blockHash, stateRoot)
stateNode1.mockStateRootLookup(contentValue.blockHash, stateRoot)
stateNode2.mockStateRootLookup(contentValue.blockHash, stateRoot)
await stateNode1.portalProtocol.gossipOffer(
Opt.none(NodeId),

View File

@ -61,8 +61,8 @@ procSuite "State Gossip - Gossip Offer":
parentContentValueBytes = parentTestData.content_value_offer.hexToSeqByte()
# set valid state root
stateNode1.mockBlockHashToStateRoot(contentValue.blockHash, stateRoot)
stateNode2.mockBlockHashToStateRoot(contentValue.blockHash, stateRoot)
stateNode1.mockStateRootLookup(contentValue.blockHash, stateRoot)
stateNode2.mockStateRootLookup(contentValue.blockHash, stateRoot)
check not stateNode2.containsId(contentId)
@ -134,8 +134,8 @@ procSuite "State Gossip - Gossip Offer":
parentContentValueBytes = parentTestData.content_value_offer.hexToSeqByte()
# set valid state root
stateNode1.mockBlockHashToStateRoot(contentValue.blockHash, stateRoot)
stateNode2.mockBlockHashToStateRoot(contentValue.blockHash, stateRoot)
stateNode1.mockStateRootLookup(contentValue.blockHash, stateRoot)
stateNode2.mockStateRootLookup(contentValue.blockHash, stateRoot)
check not stateNode2.containsId(contentId)
@ -198,8 +198,8 @@ procSuite "State Gossip - Gossip Offer":
contentValue = ContractCodeOffer.decode(contentValueBytes).get()
# set valid state root
stateNode1.mockBlockHashToStateRoot(contentValue.blockHash, stateRoot)
stateNode2.mockBlockHashToStateRoot(contentValue.blockHash, stateRoot)
stateNode1.mockStateRootLookup(contentValue.blockHash, stateRoot)
stateNode2.mockStateRootLookup(contentValue.blockHash, stateRoot)
check not stateNode2.containsId(contentId)

View File

@ -62,7 +62,7 @@ procSuite "State Network - Offer Content":
let badStateRoot = KeccakHash.fromBytes(
"0xBAD7b80af0c28bc1489513346d2706885be90abb07f23ca28e50482adb392d61".hexToSeqByte()
)
stateNode1.mockBlockHashToStateRoot(contentValue.blockHash, badStateRoot)
stateNode1.mockStateRootLookup(contentValue.blockHash, badStateRoot)
check (
await stateNode1.stateNetwork.processOffer(
Opt.none(NodeId),
@ -74,7 +74,7 @@ procSuite "State Network - Offer Content":
).isErr()
# set valid state root
stateNode1.mockBlockHashToStateRoot(contentValue.blockHash, stateRoot)
stateNode1.mockStateRootLookup(contentValue.blockHash, stateRoot)
check not stateNode1.containsId(contentId)
@ -131,7 +131,7 @@ procSuite "State Network - Offer Content":
let badStateRoot = KeccakHash.fromBytes(
"0xBAD7b80af0c28bc1489513346d2706885be90abb07f23ca28e50482adb392d61".hexToSeqByte()
)
stateNode1.mockBlockHashToStateRoot(contentValue.blockHash, badStateRoot)
stateNode1.mockStateRootLookup(contentValue.blockHash, badStateRoot)
check (
await stateNode1.stateNetwork.processOffer(
Opt.none(NodeId),
@ -143,7 +143,7 @@ procSuite "State Network - Offer Content":
).isErr()
# set valid state root
stateNode1.mockBlockHashToStateRoot(contentValue.blockHash, stateRoot)
stateNode1.mockStateRootLookup(contentValue.blockHash, stateRoot)
check not stateNode1.containsId(contentId)
@ -201,7 +201,7 @@ procSuite "State Network - Offer Content":
let badStateRoot = KeccakHash.fromBytes(
"0xBAD7b80af0c28bc1489513346d2706885be90abb07f23ca28e50482adb392d61".hexToSeqByte()
)
stateNode1.mockBlockHashToStateRoot(contentValue.blockHash, badStateRoot)
stateNode1.mockStateRootLookup(contentValue.blockHash, badStateRoot)
check (
await stateNode1.stateNetwork.processOffer(
Opt.none(NodeId),
@ -213,7 +213,7 @@ procSuite "State Network - Offer Content":
).isErr()
# set valid state root
stateNode1.mockBlockHashToStateRoot(contentValue.blockHash, stateRoot)
stateNode1.mockStateRootLookup(contentValue.blockHash, stateRoot)
check not stateNode1.containsId(contentId)
@ -265,8 +265,8 @@ procSuite "State Network - Offer Content":
(await stateNode1.portalProtocol().ping(stateNode2.localNode())).isOk()
# set valid state root
stateNode1.mockBlockHashToStateRoot(contentValue.blockHash, stateRoot)
stateNode2.mockBlockHashToStateRoot(contentValue.blockHash, stateRoot)
stateNode1.mockStateRootLookup(contentValue.blockHash, stateRoot)
stateNode2.mockStateRootLookup(contentValue.blockHash, stateRoot)
check not stateNode2.containsId(contentId)
@ -315,8 +315,8 @@ procSuite "State Network - Offer Content":
(await stateNode1.portalProtocol().ping(stateNode2.localNode())).isOk()
# set valid state root
stateNode1.mockBlockHashToStateRoot(contentValue.blockHash, stateRoot)
stateNode2.mockBlockHashToStateRoot(contentValue.blockHash, stateRoot)
stateNode1.mockStateRootLookup(contentValue.blockHash, stateRoot)
stateNode2.mockStateRootLookup(contentValue.blockHash, stateRoot)
check not stateNode2.containsId(contentId)
@ -366,8 +366,8 @@ procSuite "State Network - Offer Content":
(await stateNode1.portalProtocol().ping(stateNode2.localNode())).isOk()
# set valid state root
stateNode1.mockBlockHashToStateRoot(contentValue.blockHash, stateRoot)
stateNode2.mockBlockHashToStateRoot(contentValue.blockHash, stateRoot)
stateNode1.mockStateRootLookup(contentValue.blockHash, stateRoot)
stateNode2.mockStateRootLookup(contentValue.blockHash, stateRoot)
check not stateNode2.containsId(contentId)