Fluffy: Implement poke in state network (#2750)
* Implement poke in state network.
This commit is contained in:
parent
5e90522e70
commit
23a43d1d15
|
@ -60,12 +60,12 @@ type
|
||||||
|
|
||||||
ContentKeyType* = AccountTrieNodeKey | ContractTrieNodeKey | ContractCodeKey
|
ContentKeyType* = AccountTrieNodeKey | ContractTrieNodeKey | ContractCodeKey
|
||||||
|
|
||||||
func init*(T: type AccountTrieNodeKey, path: Nibbles, nodeHash: Hash32): T {.inline.} =
|
func init*(T: type AccountTrieNodeKey, path: Nibbles, nodeHash: Hash32): T =
|
||||||
T(path: path, nodeHash: nodeHash)
|
T(path: path, nodeHash: nodeHash)
|
||||||
|
|
||||||
func init*(
|
func init*(
|
||||||
T: type ContractTrieNodeKey, addressHash: Hash32, path: Nibbles, nodeHash: Hash32
|
T: type ContractTrieNodeKey, addressHash: Hash32, path: Nibbles, nodeHash: Hash32
|
||||||
): T {.inline.} =
|
): T =
|
||||||
T(addressHash: addressHash, path: path, nodeHash: nodeHash)
|
T(addressHash: addressHash, path: path, nodeHash: nodeHash)
|
||||||
|
|
||||||
func init*(
|
func init*(
|
||||||
|
@ -73,13 +73,13 @@ func init*(
|
||||||
): T {.inline.} =
|
): T {.inline.} =
|
||||||
T(addressHash: addressHash, codeHash: codeHash)
|
T(addressHash: addressHash, codeHash: codeHash)
|
||||||
|
|
||||||
func toContentKey*(key: AccountTrieNodeKey): ContentKey {.inline.} =
|
template toContentKey*(key: AccountTrieNodeKey): ContentKey =
|
||||||
ContentKey(contentType: accountTrieNode, accountTrieNodeKey: key)
|
ContentKey(contentType: accountTrieNode, accountTrieNodeKey: key)
|
||||||
|
|
||||||
func toContentKey*(key: ContractTrieNodeKey): ContentKey {.inline.} =
|
template toContentKey*(key: ContractTrieNodeKey): ContentKey =
|
||||||
ContentKey(contentType: contractTrieNode, contractTrieNodeKey: key)
|
ContentKey(contentType: contractTrieNode, contractTrieNodeKey: key)
|
||||||
|
|
||||||
func toContentKey*(key: ContractCodeKey): ContentKey {.inline.} =
|
template toContentKey*(key: ContractCodeKey): ContentKey =
|
||||||
ContentKey(contentType: contractCode, contractCodeKey: key)
|
ContentKey(contentType: contractCode, contractCodeKey: key)
|
||||||
|
|
||||||
proc readSszBytes*(data: openArray[byte], val: var ContentKey) {.raises: [SszError].} =
|
proc readSszBytes*(data: openArray[byte], val: var ContentKey) {.raises: [SszError].} =
|
||||||
|
@ -89,7 +89,7 @@ proc readSszBytes*(data: openArray[byte], val: var ContentKey) {.raises: [SszErr
|
||||||
|
|
||||||
readSszValue(data, val)
|
readSszValue(data, val)
|
||||||
|
|
||||||
func encode*(contentKey: ContentKey): ContentKeyByteList {.inline.} =
|
func encode*(contentKey: ContentKey): ContentKeyByteList =
|
||||||
doAssert(contentKey.contentType != unused)
|
doAssert(contentKey.contentType != unused)
|
||||||
ContentKeyByteList.init(SSZ.encode(contentKey))
|
ContentKeyByteList.init(SSZ.encode(contentKey))
|
||||||
|
|
||||||
|
@ -101,6 +101,6 @@ func decode*(
|
||||||
return err("ContentKey contentType: unused")
|
return err("ContentKey contentType: unused")
|
||||||
ok(key)
|
ok(key)
|
||||||
|
|
||||||
func toContentId*(contentKey: ContentKeyByteList): ContentId {.inline.} =
|
func toContentId*(contentKey: ContentKeyByteList): ContentId =
|
||||||
let idHash = sha256.digest(contentKey.asSeq())
|
let idHash = sha256.digest(contentKey.asSeq())
|
||||||
readUintBE[256](idHash.data)
|
readUintBE[256](idHash.data)
|
||||||
|
|
|
@ -52,12 +52,10 @@ type
|
||||||
AccountTrieNodeRetrieval | ContractTrieNodeRetrieval | ContractCodeRetrieval
|
AccountTrieNodeRetrieval | ContractTrieNodeRetrieval | ContractCodeRetrieval
|
||||||
ContentValueType* = ContentOfferType | ContentRetrievalType
|
ContentValueType* = ContentOfferType | ContentRetrievalType
|
||||||
|
|
||||||
func init*(
|
func init*(T: type AccountTrieNodeOffer, proof: TrieProof, blockHash: Hash32): T =
|
||||||
T: type AccountTrieNodeOffer, proof: TrieProof, blockHash: Hash32
|
|
||||||
): T {.inline.} =
|
|
||||||
T(proof: proof, blockHash: blockHash)
|
T(proof: proof, blockHash: blockHash)
|
||||||
|
|
||||||
func init*(T: type AccountTrieNodeRetrieval, node: TrieNode): T {.inline.} =
|
func init*(T: type AccountTrieNodeRetrieval, node: TrieNode): T =
|
||||||
T(node: node)
|
T(node: node)
|
||||||
|
|
||||||
func init*(
|
func init*(
|
||||||
|
@ -65,10 +63,10 @@ func init*(
|
||||||
storageProof: TrieProof,
|
storageProof: TrieProof,
|
||||||
accountProof: TrieProof,
|
accountProof: TrieProof,
|
||||||
blockHash: Hash32,
|
blockHash: Hash32,
|
||||||
): T {.inline.} =
|
): T =
|
||||||
T(storageProof: storageProof, accountProof: accountProof, blockHash: blockHash)
|
T(storageProof: storageProof, accountProof: accountProof, blockHash: blockHash)
|
||||||
|
|
||||||
func init*(T: type ContractTrieNodeRetrieval, node: TrieNode): T {.inline.} =
|
func init*(T: type ContractTrieNodeRetrieval, node: TrieNode): T =
|
||||||
T(node: node)
|
T(node: node)
|
||||||
|
|
||||||
func init*(
|
func init*(
|
||||||
|
@ -76,35 +74,50 @@ func init*(
|
||||||
code: Bytecode,
|
code: Bytecode,
|
||||||
accountProof: TrieProof,
|
accountProof: TrieProof,
|
||||||
blockHash: Hash32,
|
blockHash: Hash32,
|
||||||
): T {.inline.} =
|
): T =
|
||||||
T(code: code, accountProof: accountProof, blockHash: blockHash)
|
T(code: code, accountProof: accountProof, blockHash: blockHash)
|
||||||
|
|
||||||
func init*(T: type ContractCodeRetrieval, code: Bytecode): T {.inline.} =
|
func init*(T: type ContractCodeRetrieval, code: Bytecode): T =
|
||||||
T(code: code)
|
T(code: code)
|
||||||
|
|
||||||
func toRetrievalValue*(
|
template toRetrieval*(offer: AccountTrieNodeOffer): AccountTrieNodeRetrieval =
|
||||||
offer: AccountTrieNodeOffer
|
|
||||||
): AccountTrieNodeRetrieval {.inline.} =
|
|
||||||
AccountTrieNodeRetrieval.init(offer.proof[^1])
|
AccountTrieNodeRetrieval.init(offer.proof[^1])
|
||||||
|
|
||||||
func toRetrievalValue*(
|
template toRetrieval*(offer: ContractTrieNodeOffer): ContractTrieNodeRetrieval =
|
||||||
offer: ContractTrieNodeOffer
|
|
||||||
): ContractTrieNodeRetrieval {.inline.} =
|
|
||||||
ContractTrieNodeRetrieval.init(offer.storageProof[^1])
|
ContractTrieNodeRetrieval.init(offer.storageProof[^1])
|
||||||
|
|
||||||
func toRetrievalValue*(offer: ContractCodeOffer): ContractCodeRetrieval {.inline.} =
|
template toRetrieval*(offer: ContractCodeOffer): ContractCodeRetrieval =
|
||||||
ContractCodeRetrieval.init(offer.code)
|
ContractCodeRetrieval.init(offer.code)
|
||||||
|
|
||||||
func empty*(T: type TrieProof): T {.inline.} =
|
func toOffer*(
|
||||||
|
retrieval: AccountTrieNodeRetrieval, parent: AccountTrieNodeOffer
|
||||||
|
): AccountTrieNodeOffer =
|
||||||
|
var proof = parent.proof
|
||||||
|
let added = proof.add(retrieval.node)
|
||||||
|
doAssert(added)
|
||||||
|
AccountTrieNodeOffer.init(proof, parent.blockHash)
|
||||||
|
|
||||||
|
func toOffer*(
|
||||||
|
retrieval: ContractTrieNodeRetrieval, parent: ContractTrieNodeOffer
|
||||||
|
): ContractTrieNodeOffer =
|
||||||
|
var proof = parent.storageProof
|
||||||
|
let added = proof.add(retrieval.node)
|
||||||
|
doAssert(added)
|
||||||
|
ContractTrieNodeOffer.init(proof, parent.accountProof, parent.blockHash)
|
||||||
|
|
||||||
|
func toOffer*(
|
||||||
|
retrieval: ContractCodeRetrieval, parent: ContractCodeOffer
|
||||||
|
): ContractCodeOffer =
|
||||||
|
ContractCodeOffer.init(retrieval.code, parent.accountProof, parent.blockHash)
|
||||||
|
|
||||||
|
template empty*(T: type TrieProof): T =
|
||||||
T.init(@[])
|
T.init(@[])
|
||||||
|
|
||||||
func empty*(T: type Bytecode): T {.inline.} =
|
template empty*(T: type Bytecode): T =
|
||||||
T(@[])
|
T(@[])
|
||||||
|
|
||||||
func encode*(value: ContentValueType): seq[byte] {.inline.} =
|
func encode*(value: ContentValueType): seq[byte] =
|
||||||
SSZ.encode(value)
|
SSZ.encode(value)
|
||||||
|
|
||||||
func decode*(
|
func decode*(T: type ContentValueType, bytes: openArray[byte]): Result[T, string] =
|
||||||
T: type ContentValueType, bytes: openArray[byte]
|
|
||||||
): Result[T, string] {.inline.} =
|
|
||||||
decodeSsz(bytes, T)
|
decodeSsz(bytes, T)
|
||||||
|
|
|
@ -16,7 +16,9 @@ import
|
||||||
./state_network,
|
./state_network,
|
||||||
./state_utils
|
./state_utils
|
||||||
|
|
||||||
export results, state_network
|
from eth/common/eth_types_rlp import rlpHash
|
||||||
|
|
||||||
|
export results, state_network, hashes, addresses
|
||||||
|
|
||||||
logScope:
|
logScope:
|
||||||
topics = "portal_state"
|
topics = "portal_state"
|
||||||
|
@ -72,7 +74,10 @@ proc getNextNodeHash(
|
||||||
raiseAssert(e.msg)
|
raiseAssert(e.msg)
|
||||||
|
|
||||||
proc getAccountProof(
|
proc getAccountProof(
|
||||||
n: StateNetwork, stateRoot: Hash32, address: Address
|
n: StateNetwork,
|
||||||
|
stateRoot: Hash32,
|
||||||
|
address: Address,
|
||||||
|
maybeBlockHash: Opt[Hash32], # required for poke
|
||||||
): Future[Result[(TrieProof, bool), string]] {.async: (raises: [CancelledError]).} =
|
): Future[Result[(TrieProof, bool), string]] {.async: (raises: [CancelledError]).} =
|
||||||
let nibbles = address.toPath().unpackNibbles()
|
let nibbles = address.toPath().unpackNibbles()
|
||||||
|
|
||||||
|
@ -81,15 +86,26 @@ proc getAccountProof(
|
||||||
key = AccountTrieNodeKey.init(Nibbles.empty(), stateRoot)
|
key = AccountTrieNodeKey.init(Nibbles.empty(), stateRoot)
|
||||||
proof = TrieProof.empty()
|
proof = TrieProof.empty()
|
||||||
|
|
||||||
while nibblesIdx < nibbles.len():
|
# Construct the parent offer which is used to provide the data needed to
|
||||||
let accountTrieNode = (await n.getAccountTrieNode(key)).valueOr:
|
# implement poke after the account trie node has been retrieved
|
||||||
return err("Failed to get account trie node when building account proof")
|
maybeParentOffer =
|
||||||
|
if maybeBlockHash.isSome():
|
||||||
|
Opt.some(AccountTrieNodeOffer.init(proof, maybeBlockHash.get()))
|
||||||
|
else:
|
||||||
|
Opt.none(AccountTrieNodeOffer)
|
||||||
|
|
||||||
|
while nibblesIdx < nibbles.len():
|
||||||
let
|
let
|
||||||
|
accountTrieNode = (await n.getAccountTrieNode(key, maybeParentOffer)).valueOr:
|
||||||
|
return err("Failed to get account trie node when building account proof")
|
||||||
trieNode = accountTrieNode.node
|
trieNode = accountTrieNode.node
|
||||||
added = proof.add(trieNode)
|
added = proof.add(trieNode)
|
||||||
doAssert(added)
|
doAssert(added)
|
||||||
|
|
||||||
|
if maybeParentOffer.isSome():
|
||||||
|
let added = maybeParentOffer.get().proof.add(trieNode)
|
||||||
|
doAssert(added)
|
||||||
|
|
||||||
let (nextPath, nextNodeHash) = trieNode.getNextNodeHash(nibbles, nibblesIdx).valueOr:
|
let (nextPath, nextNodeHash) = trieNode.getNextNodeHash(nibbles, nibblesIdx).valueOr:
|
||||||
break
|
break
|
||||||
|
|
||||||
|
@ -99,7 +115,12 @@ proc getAccountProof(
|
||||||
ok((proof, nibblesIdx == nibbles.len()))
|
ok((proof, nibblesIdx == nibbles.len()))
|
||||||
|
|
||||||
proc getStorageProof(
|
proc getStorageProof(
|
||||||
n: StateNetwork, storageRoot: Hash32, address: Address, slotKey: UInt256
|
n: StateNetwork,
|
||||||
|
storageRoot: Hash32,
|
||||||
|
address: Address,
|
||||||
|
slotKey: UInt256,
|
||||||
|
maybeBlockHash: Opt[Hash32],
|
||||||
|
maybeAccProof: Opt[TrieProof],
|
||||||
): Future[Result[(TrieProof, bool), string]] {.async: (raises: [CancelledError]).} =
|
): Future[Result[(TrieProof, bool), string]] {.async: (raises: [CancelledError]).} =
|
||||||
let nibbles = slotKey.toPath().unpackNibbles()
|
let nibbles = slotKey.toPath().unpackNibbles()
|
||||||
|
|
||||||
|
@ -109,15 +130,29 @@ proc getStorageProof(
|
||||||
key = ContractTrieNodeKey.init(addressHash, Nibbles.empty(), storageRoot)
|
key = ContractTrieNodeKey.init(addressHash, Nibbles.empty(), storageRoot)
|
||||||
proof = TrieProof.empty()
|
proof = TrieProof.empty()
|
||||||
|
|
||||||
while nibblesIdx < nibbles.len():
|
# Construct the parent offer which is used to provide the data needed to
|
||||||
let contractTrieNode = (await n.getContractTrieNode(key)).valueOr:
|
# implement poke after the contract trie node has been retrieved
|
||||||
return err("Failed to get contract trie node when building account proof")
|
maybeParentOffer =
|
||||||
|
if maybeBlockHash.isSome():
|
||||||
|
doAssert maybeAccProof.isSome()
|
||||||
|
Opt.some(
|
||||||
|
ContractTrieNodeOffer.init(proof, maybeAccProof.get(), maybeBlockHash.get())
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
Opt.none(ContractTrieNodeOffer)
|
||||||
|
|
||||||
|
while nibblesIdx < nibbles.len():
|
||||||
let
|
let
|
||||||
|
contractTrieNode = (await n.getContractTrieNode(key, maybeParentOffer)).valueOr:
|
||||||
|
return err("Failed to get contract trie node when building storage proof")
|
||||||
trieNode = contractTrieNode.node
|
trieNode = contractTrieNode.node
|
||||||
added = proof.add(trieNode)
|
added = proof.add(trieNode)
|
||||||
doAssert(added)
|
doAssert(added)
|
||||||
|
|
||||||
|
if maybeParentOffer.isSome():
|
||||||
|
let added = maybeParentOffer.get().storageProof.add(trieNode)
|
||||||
|
doAssert(added)
|
||||||
|
|
||||||
let (nextPath, nextNodeHash) = trieNode.getNextNodeHash(nibbles, nibblesIdx).valueOr:
|
let (nextPath, nextNodeHash) = trieNode.getNextNodeHash(nibbles, nibblesIdx).valueOr:
|
||||||
break
|
break
|
||||||
|
|
||||||
|
@ -127,9 +162,11 @@ proc getStorageProof(
|
||||||
ok((proof, nibblesIdx == nibbles.len()))
|
ok((proof, nibblesIdx == nibbles.len()))
|
||||||
|
|
||||||
proc getAccount(
|
proc getAccount(
|
||||||
n: StateNetwork, stateRoot: Hash32, address: Address
|
n: StateNetwork, stateRoot: Hash32, address: Address, maybeBlockHash: Opt[Hash32]
|
||||||
): Future[Opt[Account]] {.async: (raises: [CancelledError]).} =
|
): Future[Opt[Account]] {.async: (raises: [CancelledError]).} =
|
||||||
let (accountProof, exists) = (await n.getAccountProof(stateRoot, address)).valueOr:
|
let (accountProof, exists) = (
|
||||||
|
await n.getAccountProof(stateRoot, address, maybeBlockHash)
|
||||||
|
).valueOr:
|
||||||
warn "Failed to get account proof", error = error
|
warn "Failed to get account proof", error = error
|
||||||
return Opt.none(Account)
|
return Opt.none(Account)
|
||||||
|
|
||||||
|
@ -145,39 +182,64 @@ proc getAccount(
|
||||||
Opt.some(account)
|
Opt.some(account)
|
||||||
|
|
||||||
proc getBalanceByStateRoot*(
|
proc getBalanceByStateRoot*(
|
||||||
n: StateNetwork, stateRoot: Hash32, address: Address
|
n: StateNetwork,
|
||||||
|
stateRoot: Hash32,
|
||||||
|
address: Address,
|
||||||
|
maybeBlockHash = Opt.none(Hash32),
|
||||||
): Future[Opt[UInt256]] {.async: (raises: [CancelledError]).} =
|
): Future[Opt[UInt256]] {.async: (raises: [CancelledError]).} =
|
||||||
let account = (await n.getAccount(stateRoot, address)).valueOr:
|
let account = (await n.getAccount(stateRoot, address, maybeBlockHash)).valueOr:
|
||||||
return Opt.none(UInt256)
|
return Opt.none(UInt256)
|
||||||
|
|
||||||
Opt.some(account.balance)
|
Opt.some(account.balance)
|
||||||
|
|
||||||
proc getTransactionCountByStateRoot*(
|
proc getTransactionCountByStateRoot*(
|
||||||
n: StateNetwork, stateRoot: Hash32, address: Address
|
n: StateNetwork,
|
||||||
|
stateRoot: Hash32,
|
||||||
|
address: Address,
|
||||||
|
maybeBlockHash = Opt.none(Hash32),
|
||||||
): Future[Opt[AccountNonce]] {.async: (raises: [CancelledError]).} =
|
): Future[Opt[AccountNonce]] {.async: (raises: [CancelledError]).} =
|
||||||
let account = (await n.getAccount(stateRoot, address)).valueOr:
|
let account = (await n.getAccount(stateRoot, address, maybeBlockHash)).valueOr:
|
||||||
return Opt.none(AccountNonce)
|
return Opt.none(AccountNonce)
|
||||||
|
|
||||||
Opt.some(account.nonce)
|
Opt.some(account.nonce)
|
||||||
|
|
||||||
proc getStorageAtByStateRoot*(
|
proc getStorageAtByStateRoot*(
|
||||||
n: StateNetwork, stateRoot: Hash32, address: Address, slotKey: UInt256
|
n: StateNetwork,
|
||||||
|
stateRoot: Hash32,
|
||||||
|
address: Address,
|
||||||
|
slotKey: UInt256,
|
||||||
|
maybeBlockHash = Opt.none(Hash32),
|
||||||
): Future[Opt[UInt256]] {.async: (raises: [CancelledError]).} =
|
): Future[Opt[UInt256]] {.async: (raises: [CancelledError]).} =
|
||||||
let account = (await n.getAccount(stateRoot, address)).valueOr:
|
let (accountProof, exists) = (
|
||||||
|
await n.getAccountProof(stateRoot, address, maybeBlockHash)
|
||||||
|
).valueOr:
|
||||||
|
warn "Failed to get account proof", error = error
|
||||||
return Opt.none(UInt256)
|
return Opt.none(UInt256)
|
||||||
|
|
||||||
|
let account =
|
||||||
|
if exists:
|
||||||
|
accountProof.toAccount().valueOr:
|
||||||
|
error "Failed to get account from accountProof"
|
||||||
|
return Opt.none(UInt256)
|
||||||
|
else:
|
||||||
|
info "Account doesn't exist, returning default account"
|
||||||
|
# return an empty account if the account doesn't exist
|
||||||
|
EMPTY_ACCOUNT
|
||||||
|
|
||||||
if account.storageRoot == EMPTY_ROOT_HASH:
|
if account.storageRoot == EMPTY_ROOT_HASH:
|
||||||
info "Storage doesn't exist, returning default storage value"
|
info "Storage doesn't exist, returning default storage value"
|
||||||
# return zero if the storage doesn't exist
|
# return zero if the storage doesn't exist
|
||||||
return Opt.some(0.u256)
|
return Opt.some(0.u256)
|
||||||
|
|
||||||
let (storageProof, exists) = (
|
let (storageProof, slotExists) = (
|
||||||
await n.getStorageProof(account.storageRoot, address, slotKey)
|
await n.getStorageProof(
|
||||||
|
account.storageRoot, address, slotKey, maybeBlockHash, Opt.some(accountProof)
|
||||||
|
)
|
||||||
).valueOr:
|
).valueOr:
|
||||||
warn "Failed to get storage proof", error = error
|
warn "Failed to get storage proof", error = error
|
||||||
return Opt.none(UInt256)
|
return Opt.none(UInt256)
|
||||||
|
|
||||||
if not exists:
|
if not slotExists:
|
||||||
info "Slot doesn't exist, returning default storage value"
|
info "Slot doesn't exist, returning default storage value"
|
||||||
# return zero if the slot doesn't exist
|
# return zero if the slot doesn't exist
|
||||||
return Opt.some(0.u256)
|
return Opt.some(0.u256)
|
||||||
|
@ -189,11 +251,27 @@ proc getStorageAtByStateRoot*(
|
||||||
Opt.some(slotValue)
|
Opt.some(slotValue)
|
||||||
|
|
||||||
proc getCodeByStateRoot*(
|
proc getCodeByStateRoot*(
|
||||||
n: StateNetwork, stateRoot: Hash32, address: Address
|
n: StateNetwork,
|
||||||
|
stateRoot: Hash32,
|
||||||
|
address: Address,
|
||||||
|
maybeBlockHash = Opt.none(Hash32),
|
||||||
): Future[Opt[Bytecode]] {.async: (raises: [CancelledError]).} =
|
): Future[Opt[Bytecode]] {.async: (raises: [CancelledError]).} =
|
||||||
let account = (await n.getAccount(stateRoot, address)).valueOr:
|
let (accountProof, exists) = (
|
||||||
|
await n.getAccountProof(stateRoot, address, maybeBlockHash)
|
||||||
|
).valueOr:
|
||||||
|
warn "Failed to get account proof", error = error
|
||||||
return Opt.none(Bytecode)
|
return Opt.none(Bytecode)
|
||||||
|
|
||||||
|
let account =
|
||||||
|
if exists:
|
||||||
|
accountProof.toAccount().valueOr:
|
||||||
|
error "Failed to get account from accountProof"
|
||||||
|
return Opt.none(Bytecode)
|
||||||
|
else:
|
||||||
|
info "Account doesn't exist, returning default account"
|
||||||
|
# return an empty account if the account doesn't exist
|
||||||
|
EMPTY_ACCOUNT
|
||||||
|
|
||||||
if account.codeHash == EMPTY_CODE_HASH:
|
if account.codeHash == EMPTY_CODE_HASH:
|
||||||
info "Code doesn't exist, returning default code value"
|
info "Code doesn't exist, returning default code value"
|
||||||
# return empty bytecode if the code doesn't exist
|
# return empty bytecode if the code doesn't exist
|
||||||
|
@ -201,7 +279,14 @@ proc getCodeByStateRoot*(
|
||||||
|
|
||||||
let
|
let
|
||||||
contractCodeKey = ContractCodeKey.init(keccak256(address.data), account.codeHash)
|
contractCodeKey = ContractCodeKey.init(keccak256(address.data), account.codeHash)
|
||||||
contractCodeRetrieval = (await n.getContractCode(contractCodeKey)).valueOr:
|
maybeParentOffer =
|
||||||
|
if maybeBlockHash.isSome():
|
||||||
|
Opt.some(
|
||||||
|
ContractCodeOffer.init(Bytecode.empty(), accountProof, maybeBlockHash.get())
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
Opt.none(ContractCodeOffer)
|
||||||
|
contractCodeRetrieval = (await n.getContractCode(contractCodeKey, maybeParentOffer)).valueOr:
|
||||||
warn "Failed to get contract code"
|
warn "Failed to get contract code"
|
||||||
return Opt.none(Bytecode)
|
return Opt.none(Bytecode)
|
||||||
|
|
||||||
|
@ -214,10 +299,16 @@ type Proofs* = ref object
|
||||||
slotProofs*: seq[TrieProof]
|
slotProofs*: seq[TrieProof]
|
||||||
|
|
||||||
proc getProofsByStateRoot*(
|
proc getProofsByStateRoot*(
|
||||||
n: StateNetwork, stateRoot: Hash32, address: Address, slotKeys: seq[UInt256]
|
n: StateNetwork,
|
||||||
|
stateRoot: Hash32,
|
||||||
|
address: Address,
|
||||||
|
slotKeys: seq[UInt256],
|
||||||
|
maybeBlockHash = Opt.none(Hash32),
|
||||||
): Future[Opt[Proofs]] {.async: (raises: [CancelledError]).} =
|
): Future[Opt[Proofs]] {.async: (raises: [CancelledError]).} =
|
||||||
let
|
let
|
||||||
(accountProof, accountExists) = (await n.getAccountProof(stateRoot, address)).valueOr:
|
(accountProof, accountExists) = (
|
||||||
|
await n.getAccountProof(stateRoot, address, maybeBlockHash)
|
||||||
|
).valueOr:
|
||||||
warn "Failed to get account proof", error = error
|
warn "Failed to get account proof", error = error
|
||||||
return Opt.none(Proofs)
|
return Opt.none(Proofs)
|
||||||
account =
|
account =
|
||||||
|
@ -241,7 +332,9 @@ proc getProofsByStateRoot*(
|
||||||
|
|
||||||
let
|
let
|
||||||
(storageProof, slotExists) = (
|
(storageProof, slotExists) = (
|
||||||
await n.getStorageProof(account.storageRoot, address, slotKey)
|
await n.getStorageProof(
|
||||||
|
account.storageRoot, address, slotKey, maybeBlockHash, Opt.some(accountProof)
|
||||||
|
)
|
||||||
).valueOr:
|
).valueOr:
|
||||||
warn "Failed to get storage proof", error = error
|
warn "Failed to get storage proof", error = error
|
||||||
return Opt.none(Proofs)
|
return Opt.none(Proofs)
|
||||||
|
@ -265,41 +358,45 @@ proc getProofsByStateRoot*(
|
||||||
proc getBalance*(
|
proc getBalance*(
|
||||||
n: StateNetwork, blockNumOrHash: uint64 | Hash32, address: Address
|
n: StateNetwork, blockNumOrHash: uint64 | Hash32, address: Address
|
||||||
): Future[Opt[UInt256]] {.async: (raises: [CancelledError]).} =
|
): Future[Opt[UInt256]] {.async: (raises: [CancelledError]).} =
|
||||||
let stateRoot = (await n.getStateRootByBlockNumOrHash(blockNumOrHash)).valueOr:
|
let header = (await n.getBlockHeaderByBlockNumOrHash(blockNumOrHash)).valueOr:
|
||||||
warn "Failed to get state root by block number or hash", blockNumOrHash
|
warn "Failed to get block header by block number or hash", blockNumOrHash
|
||||||
return Opt.none(UInt256)
|
return Opt.none(UInt256)
|
||||||
|
|
||||||
await n.getBalanceByStateRoot(stateRoot, address)
|
await n.getBalanceByStateRoot(header.stateRoot, address, Opt.some(header.rlpHash()))
|
||||||
|
|
||||||
# Used by: eth_getTransactionCount
|
# Used by: eth_getTransactionCount
|
||||||
proc getTransactionCount*(
|
proc getTransactionCount*(
|
||||||
n: StateNetwork, blockNumOrHash: uint64 | Hash32, address: Address
|
n: StateNetwork, blockNumOrHash: uint64 | Hash32, address: Address
|
||||||
): Future[Opt[AccountNonce]] {.async: (raises: [CancelledError]).} =
|
): Future[Opt[AccountNonce]] {.async: (raises: [CancelledError]).} =
|
||||||
let stateRoot = (await n.getStateRootByBlockNumOrHash(blockNumOrHash)).valueOr:
|
let header = (await n.getBlockHeaderByBlockNumOrHash(blockNumOrHash)).valueOr:
|
||||||
warn "Failed to get state root by block number or hash", blockNumOrHash
|
warn "Failed to get block header by block number or hash", blockNumOrHash
|
||||||
return Opt.none(AccountNonce)
|
return Opt.none(AccountNonce)
|
||||||
|
|
||||||
await n.getTransactionCountByStateRoot(stateRoot, address)
|
await n.getTransactionCountByStateRoot(
|
||||||
|
header.stateRoot, address, Opt.some(header.rlpHash())
|
||||||
|
)
|
||||||
|
|
||||||
# Used by: eth_getStorageAt
|
# Used by: eth_getStorageAt
|
||||||
proc getStorageAt*(
|
proc getStorageAt*(
|
||||||
n: StateNetwork, blockNumOrHash: uint64 | Hash32, address: Address, slotKey: UInt256
|
n: StateNetwork, blockNumOrHash: uint64 | Hash32, address: Address, slotKey: UInt256
|
||||||
): Future[Opt[UInt256]] {.async: (raises: [CancelledError]).} =
|
): Future[Opt[UInt256]] {.async: (raises: [CancelledError]).} =
|
||||||
let stateRoot = (await n.getStateRootByBlockNumOrHash(blockNumOrHash)).valueOr:
|
let header = (await n.getBlockHeaderByBlockNumOrHash(blockNumOrHash)).valueOr:
|
||||||
warn "Failed to get state root by block number or hash", blockNumOrHash
|
warn "Failed to get block header by block number or hash", blockNumOrHash
|
||||||
return Opt.none(UInt256)
|
return Opt.none(UInt256)
|
||||||
|
|
||||||
await n.getStorageAtByStateRoot(stateRoot, address, slotKey)
|
await n.getStorageAtByStateRoot(
|
||||||
|
header.stateRoot, address, slotKey, Opt.some(header.rlpHash())
|
||||||
|
)
|
||||||
|
|
||||||
# Used by: eth_getCode
|
# Used by: eth_getCode
|
||||||
proc getCode*(
|
proc getCode*(
|
||||||
n: StateNetwork, blockNumOrHash: uint64 | Hash32, address: Address
|
n: StateNetwork, blockNumOrHash: uint64 | Hash32, address: Address
|
||||||
): Future[Opt[Bytecode]] {.async: (raises: [CancelledError]).} =
|
): Future[Opt[Bytecode]] {.async: (raises: [CancelledError]).} =
|
||||||
let stateRoot = (await n.getStateRootByBlockNumOrHash(blockNumOrHash)).valueOr:
|
let header = (await n.getBlockHeaderByBlockNumOrHash(blockNumOrHash)).valueOr:
|
||||||
warn "Failed to get state root by block number or hash", blockNumOrHash
|
warn "Failed to get block header by block number or hash", blockNumOrHash
|
||||||
return Opt.none(Bytecode)
|
return Opt.none(Bytecode)
|
||||||
|
|
||||||
await n.getCodeByStateRoot(stateRoot, address)
|
await n.getCodeByStateRoot(header.stateRoot, address, Opt.some(header.rlpHash()))
|
||||||
|
|
||||||
# Used by: eth_getProof
|
# Used by: eth_getProof
|
||||||
proc getProofs*(
|
proc getProofs*(
|
||||||
|
@ -308,8 +405,10 @@ proc getProofs*(
|
||||||
address: Address,
|
address: Address,
|
||||||
slotKeys: seq[UInt256],
|
slotKeys: seq[UInt256],
|
||||||
): Future[Opt[Proofs]] {.async: (raises: [CancelledError]).} =
|
): Future[Opt[Proofs]] {.async: (raises: [CancelledError]).} =
|
||||||
let stateRoot = (await n.getStateRootByBlockNumOrHash(blockNumOrHash)).valueOr:
|
let header = (await n.getBlockHeaderByBlockNumOrHash(blockNumOrHash)).valueOr:
|
||||||
warn "Failed to get state root by block number or hash", blockNumOrHash
|
warn "Failed to get block header by block number or hash", blockNumOrHash
|
||||||
return Opt.none(Proofs)
|
return Opt.none(Proofs)
|
||||||
|
|
||||||
await n.getProofsByStateRoot(stateRoot, address, slotKeys)
|
await n.getProofsByStateRoot(
|
||||||
|
header.stateRoot, address, slotKeys, Opt.some(header.rlpHash())
|
||||||
|
)
|
||||||
|
|
|
@ -81,8 +81,9 @@ proc new*(
|
||||||
|
|
||||||
proc getContent(
|
proc getContent(
|
||||||
n: StateNetwork,
|
n: StateNetwork,
|
||||||
key: AccountTrieNodeKey | ContractTrieNodeKey | ContractCodeKey,
|
key: ContentKeyType,
|
||||||
V: type ContentRetrievalType,
|
V: type ContentRetrievalType,
|
||||||
|
maybeParentOffer: Opt[ContentOfferType],
|
||||||
): Future[Opt[V]] {.async: (raises: [CancelledError]).} =
|
): Future[Opt[V]] {.async: (raises: [CancelledError]).} =
|
||||||
let
|
let
|
||||||
contentKeyBytes = key.toContentKey().encode()
|
contentKeyBytes = key.toContentKey().encode()
|
||||||
|
@ -118,42 +119,54 @@ proc getContent(
|
||||||
contentKeyBytes, contentId, contentValueBytes, cacheContent = true
|
contentKeyBytes, contentId, contentValueBytes, cacheContent = true
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if maybeParentOffer.isSome():
|
||||||
|
let offer = contentValue.toOffer(maybeParentOffer.get())
|
||||||
|
n.portalProtocol.triggerPoke(
|
||||||
|
contentLookupResult.nodesInterestedInContent, contentKeyBytes, offer.encode()
|
||||||
|
)
|
||||||
|
|
||||||
return Opt.some(contentValue)
|
return Opt.some(contentValue)
|
||||||
|
|
||||||
# Content was requested `1 + requestRetries` times and all failed on validation
|
# Content was requested `1 + requestRetries` times and all failed on validation
|
||||||
Opt.none(V)
|
Opt.none(V)
|
||||||
|
|
||||||
proc getAccountTrieNode*(
|
proc getAccountTrieNode*(
|
||||||
n: StateNetwork, key: AccountTrieNodeKey
|
n: StateNetwork,
|
||||||
|
key: AccountTrieNodeKey,
|
||||||
|
maybeParentOffer = Opt.none(AccountTrieNodeOffer),
|
||||||
): Future[Opt[AccountTrieNodeRetrieval]] {.
|
): Future[Opt[AccountTrieNodeRetrieval]] {.
|
||||||
async: (raw: true, raises: [CancelledError])
|
async: (raw: true, raises: [CancelledError])
|
||||||
.} =
|
.} =
|
||||||
n.getContent(key, AccountTrieNodeRetrieval)
|
n.getContent(key, AccountTrieNodeRetrieval, maybeParentOffer)
|
||||||
|
|
||||||
proc getContractTrieNode*(
|
proc getContractTrieNode*(
|
||||||
n: StateNetwork, key: ContractTrieNodeKey
|
n: StateNetwork,
|
||||||
|
key: ContractTrieNodeKey,
|
||||||
|
maybeParentOffer = Opt.none(ContractTrieNodeOffer),
|
||||||
): Future[Opt[ContractTrieNodeRetrieval]] {.
|
): Future[Opt[ContractTrieNodeRetrieval]] {.
|
||||||
async: (raw: true, raises: [CancelledError])
|
async: (raw: true, raises: [CancelledError])
|
||||||
.} =
|
.} =
|
||||||
n.getContent(key, ContractTrieNodeRetrieval)
|
n.getContent(key, ContractTrieNodeRetrieval, maybeParentOffer)
|
||||||
|
|
||||||
proc getContractCode*(
|
proc getContractCode*(
|
||||||
n: StateNetwork, key: ContractCodeKey
|
n: StateNetwork,
|
||||||
|
key: ContractCodeKey,
|
||||||
|
maybeParentOffer = Opt.none(ContractCodeOffer),
|
||||||
): Future[Opt[ContractCodeRetrieval]] {.async: (raw: true, raises: [CancelledError]).} =
|
): Future[Opt[ContractCodeRetrieval]] {.async: (raw: true, raises: [CancelledError]).} =
|
||||||
n.getContent(key, ContractCodeRetrieval)
|
n.getContent(key, ContractCodeRetrieval, maybeParentOffer)
|
||||||
|
|
||||||
proc getStateRootByBlockNumOrHash*(
|
proc getBlockHeaderByBlockNumOrHash*(
|
||||||
n: StateNetwork, blockNumOrHash: uint64 | Hash32
|
n: StateNetwork, blockNumOrHash: uint64 | Hash32
|
||||||
): Future[Opt[Hash32]] {.async: (raises: [CancelledError]).} =
|
): Future[Opt[Header]] {.async: (raises: [CancelledError]).} =
|
||||||
let hn = n.historyNetwork.valueOr:
|
let hn = n.historyNetwork.valueOr:
|
||||||
warn "History network is not available"
|
warn "History network is not available"
|
||||||
return Opt.none(Hash32)
|
return Opt.none(Header)
|
||||||
|
|
||||||
let header = (await hn.getVerifiedBlockHeader(blockNumOrHash)).valueOr:
|
let header = (await hn.getVerifiedBlockHeader(blockNumOrHash)).valueOr:
|
||||||
warn "Failed to get block header from history", blockNumOrHash
|
warn "Failed to get block header from history", blockNumOrHash
|
||||||
return Opt.none(Hash32)
|
return Opt.none(Header)
|
||||||
|
|
||||||
Opt.some(header.stateRoot)
|
Opt.some(header)
|
||||||
|
|
||||||
proc processOffer*(
|
proc processOffer*(
|
||||||
n: StateNetwork,
|
n: StateNetwork,
|
||||||
|
@ -168,9 +181,9 @@ proc processOffer*(
|
||||||
return err("Unable to decode offered content value")
|
return err("Unable to decode offered content value")
|
||||||
validationRes =
|
validationRes =
|
||||||
if n.validateStateIsCanonical:
|
if n.validateStateIsCanonical:
|
||||||
let stateRoot = (await n.getStateRootByBlockNumOrHash(contentValue.blockHash)).valueOr:
|
let header = (await n.getBlockHeaderByBlockNumOrHash(contentValue.blockHash)).valueOr:
|
||||||
return err("Failed to get state root by block hash")
|
return err("Failed to get block header by hash")
|
||||||
validateOffer(Opt.some(stateRoot), contentKey, contentValue)
|
validateOffer(Opt.some(header.stateRoot), contentKey, contentValue)
|
||||||
else:
|
else:
|
||||||
# Skip state root validation
|
# Skip state root validation
|
||||||
validateOffer(Opt.none(Hash32), contentKey, contentValue)
|
validateOffer(Opt.none(Hash32), contentKey, contentValue)
|
||||||
|
@ -182,7 +195,7 @@ proc processOffer*(
|
||||||
return err("Received offered content with invalid content key")
|
return err("Received offered content with invalid content key")
|
||||||
|
|
||||||
n.portalProtocol.storeContent(
|
n.portalProtocol.storeContent(
|
||||||
contentKeyBytes, contentId, contentValue.toRetrievalValue().encode()
|
contentKeyBytes, contentId, contentValue.toRetrieval().encode()
|
||||||
)
|
)
|
||||||
|
|
||||||
await gossipOffer(
|
await gossipOffer(
|
||||||
|
|
|
@ -146,7 +146,7 @@ func validateOffer*(
|
||||||
): Result[void, string] =
|
): Result[void, string] =
|
||||||
?validateTrieProof(trustedStateRoot, key.path, offer.proof)
|
?validateTrieProof(trustedStateRoot, key.path, offer.proof)
|
||||||
|
|
||||||
validateRetrieval(key, offer.toRetrievalValue())
|
validateRetrieval(key, offer.toRetrieval())
|
||||||
|
|
||||||
func validateOffer*(
|
func validateOffer*(
|
||||||
trustedStateRoot: Opt[Hash32],
|
trustedStateRoot: Opt[Hash32],
|
||||||
|
@ -164,7 +164,7 @@ func validateOffer*(
|
||||||
|
|
||||||
?validateTrieProof(Opt.some(account.storageRoot), key.path, offer.storageProof)
|
?validateTrieProof(Opt.some(account.storageRoot), key.path, offer.storageProof)
|
||||||
|
|
||||||
validateRetrieval(key, offer.toRetrievalValue())
|
validateRetrieval(key, offer.toRetrieval())
|
||||||
|
|
||||||
func validateOffer*(
|
func validateOffer*(
|
||||||
trustedStateRoot: Opt[Hash32], key: ContractCodeKey, offer: ContractCodeOffer
|
trustedStateRoot: Opt[Hash32], key: ContractCodeKey, offer: ContractCodeOffer
|
||||||
|
@ -180,7 +180,10 @@ func validateOffer*(
|
||||||
if not offer.code.hashEquals(account.codeHash):
|
if not offer.code.hashEquals(account.codeHash):
|
||||||
return err("hash of bytecode doesn't match the code hash in the account proof")
|
return err("hash of bytecode doesn't match the code hash in the account proof")
|
||||||
|
|
||||||
validateRetrieval(key, offer.toRetrievalValue())
|
validateRetrieval(key, offer.toRetrieval())
|
||||||
|
|
||||||
|
# Local validations that check the structure of the content keys and values.
|
||||||
|
# None of the validations below check if the data is canonical or not
|
||||||
|
|
||||||
func validateGetContentKey*(
|
func validateGetContentKey*(
|
||||||
keyBytes: ContentKeyByteList
|
keyBytes: ContentKeyByteList
|
||||||
|
@ -204,24 +207,52 @@ func validateRetrieval*(
|
||||||
let retrieval = ?ContractCodeRetrieval.decode(contentBytes)
|
let retrieval = ?ContractCodeRetrieval.decode(contentBytes)
|
||||||
validateRetrieval(key.contractCodeKey, retrieval)
|
validateRetrieval(key.contractCodeKey, retrieval)
|
||||||
|
|
||||||
func validateOfferGetValue*(
|
func validateRetrievalGetOffer*(
|
||||||
trustedStateRoot: Opt[Hash32], key: ContentKey, contentBytes: seq[byte]
|
key: ContentKey, contentBytes: seq[byte], parentContentBytes: seq[byte]
|
||||||
): Result[seq[byte], string] =
|
): Result[seq[byte], string] =
|
||||||
let value =
|
case key.contentType
|
||||||
case key.contentType
|
of unused:
|
||||||
of unused:
|
raiseAssert("ContentKey contentType: unused")
|
||||||
raiseAssert("ContentKey contentType: unused")
|
of accountTrieNode:
|
||||||
of accountTrieNode:
|
let
|
||||||
let offer = ?AccountTrieNodeOffer.decode(contentBytes)
|
retrieval = ?AccountTrieNodeRetrieval.decode(contentBytes)
|
||||||
?validateOffer(trustedStateRoot, key.accountTrieNodeKey, offer)
|
parentOffer = ?AccountTrieNodeOffer.decode(parentContentBytes)
|
||||||
offer.toRetrievalValue.encode()
|
offer = retrieval.toOffer(parentOffer)
|
||||||
of contractTrieNode:
|
?validateRetrieval(key.accountTrieNodeKey, retrieval)
|
||||||
let offer = ?ContractTrieNodeOffer.decode(contentBytes)
|
?validateOffer(Opt.none(Hash32), key.accountTrieNodeKey, offer)
|
||||||
?validateOffer(trustedStateRoot, key.contractTrieNodeKey, offer)
|
ok(offer.encode())
|
||||||
offer.toRetrievalValue.encode()
|
of contractTrieNode:
|
||||||
of contractCode:
|
let
|
||||||
let offer = ?ContractCodeOffer.decode(contentBytes)
|
retrieval = ?ContractTrieNodeRetrieval.decode(contentBytes)
|
||||||
?validateOffer(trustedStateRoot, key.contractCodeKey, offer)
|
parentOffer = ?ContractTrieNodeOffer.decode(parentContentBytes)
|
||||||
offer.toRetrievalValue.encode()
|
offer = retrieval.toOffer(parentOffer)
|
||||||
|
?validateRetrieval(key.contractTrieNodeKey, retrieval)
|
||||||
|
?validateOffer(Opt.none(Hash32), key.contractTrieNodeKey, offer)
|
||||||
|
ok(offer.encode())
|
||||||
|
of contractCode:
|
||||||
|
let
|
||||||
|
retrieval = ?ContractCodeRetrieval.decode(contentBytes)
|
||||||
|
parentOffer = ?ContractCodeOffer.decode(parentContentBytes)
|
||||||
|
offer = retrieval.toOffer(parentOffer)
|
||||||
|
?validateRetrieval(key.contractCodeKey, retrieval)
|
||||||
|
?validateOffer(Opt.none(Hash32), key.contractCodeKey, offer)
|
||||||
|
ok(offer.encode())
|
||||||
|
|
||||||
ok(value)
|
func validateOfferGetRetrieval*(
|
||||||
|
key: ContentKey, contentBytes: seq[byte]
|
||||||
|
): Result[seq[byte], string] =
|
||||||
|
case key.contentType
|
||||||
|
of unused:
|
||||||
|
raiseAssert("ContentKey contentType: unused")
|
||||||
|
of accountTrieNode:
|
||||||
|
let offer = ?AccountTrieNodeOffer.decode(contentBytes)
|
||||||
|
?validateOffer(Opt.none(Hash32), key.accountTrieNodeKey, offer)
|
||||||
|
ok(offer.toRetrieval.encode())
|
||||||
|
of contractTrieNode:
|
||||||
|
let offer = ?ContractTrieNodeOffer.decode(contentBytes)
|
||||||
|
?validateOffer(Opt.none(Hash32), key.contractTrieNodeKey, offer)
|
||||||
|
ok(offer.toRetrieval.encode())
|
||||||
|
of contractCode:
|
||||||
|
let offer = ?ContractCodeOffer.decode(contentBytes)
|
||||||
|
?validateOffer(Opt.none(Hash32), key.contractCodeKey, offer)
|
||||||
|
ok(offer.toRetrieval.encode())
|
||||||
|
|
|
@ -74,7 +74,7 @@ proc installPortalStateApiHandlers*(rpcServer: RpcServer, p: PortalProtocol) =
|
||||||
contentBytes = hexToSeqByte(contentItem[1])
|
contentBytes = hexToSeqByte(contentItem[1])
|
||||||
contentKV = ContentKV(contentKey: keyBytes, content: contentBytes)
|
contentKV = ContentKV(contentKey: keyBytes, content: contentBytes)
|
||||||
|
|
||||||
discard validateOfferGetValue(Opt.none(Hash32), key, contentBytes).valueOr:
|
discard validateOfferGetRetrieval(key, contentBytes).valueOr:
|
||||||
raise invalidValueErr()
|
raise invalidValueErr()
|
||||||
contentItemsToOffer.add(contentKV)
|
contentItemsToOffer.add(contentKV)
|
||||||
|
|
||||||
|
@ -134,7 +134,7 @@ proc installPortalStateApiHandlers*(rpcServer: RpcServer, p: PortalProtocol) =
|
||||||
(key, contentId) = validateGetContentKey(keyBytes).valueOr:
|
(key, contentId) = validateGetContentKey(keyBytes).valueOr:
|
||||||
raise invalidKeyErr()
|
raise invalidKeyErr()
|
||||||
contentBytes = hexToSeqByte(content)
|
contentBytes = hexToSeqByte(content)
|
||||||
contentValue = validateOfferGetValue(Opt.none(Hash32), key, contentBytes).valueOr:
|
contentValue = validateOfferGetRetrieval(key, contentBytes).valueOr:
|
||||||
raise invalidValueErr()
|
raise invalidValueErr()
|
||||||
|
|
||||||
p.storeContent(keyBytes, contentId, contentValue)
|
p.storeContent(keyBytes, contentId, contentValue)
|
||||||
|
@ -156,7 +156,7 @@ proc installPortalStateApiHandlers*(rpcServer: RpcServer, p: PortalProtocol) =
|
||||||
(key, contentId) = validateGetContentKey(keyBytes).valueOr:
|
(key, contentId) = validateGetContentKey(keyBytes).valueOr:
|
||||||
raise invalidKeyErr()
|
raise invalidKeyErr()
|
||||||
contentBytes = hexToSeqByte(content)
|
contentBytes = hexToSeqByte(content)
|
||||||
contentValue = validateOfferGetValue(Opt.none(Hash32), key, contentBytes).valueOr:
|
contentValue = validateOfferGetRetrieval(key, contentBytes).valueOr:
|
||||||
raise invalidValueErr()
|
raise invalidValueErr()
|
||||||
|
|
||||||
p.storeContent(keyBytes, contentId, contentValue)
|
p.storeContent(keyBytes, contentId, contentValue)
|
||||||
|
|
|
@ -41,7 +41,7 @@ suite "State Endpoints - Genesis JSON Files":
|
||||||
# store the account leaf node
|
# store the account leaf node
|
||||||
let contentKey = key.toContentKey().encode()
|
let contentKey = key.toContentKey().encode()
|
||||||
stateNode.portalProtocol.storeContent(
|
stateNode.portalProtocol.storeContent(
|
||||||
contentKey, contentKey.toContentId(), offer.toRetrievalValue().encode()
|
contentKey, contentKey.toContentId(), offer.toRetrieval().encode()
|
||||||
)
|
)
|
||||||
|
|
||||||
# store the account parent nodes / all remaining nodes
|
# store the account parent nodes / all remaining nodes
|
||||||
|
@ -52,7 +52,7 @@ suite "State Endpoints - Genesis JSON Files":
|
||||||
stateNode.portalProtocol.storeContent(
|
stateNode.portalProtocol.storeContent(
|
||||||
parentContentKey,
|
parentContentKey,
|
||||||
parentContentKey.toContentId(),
|
parentContentKey.toContentId(),
|
||||||
parent.offer.toRetrievalValue().encode(),
|
parent.offer.toRetrieval().encode(),
|
||||||
)
|
)
|
||||||
|
|
||||||
for i in proof.low ..< proof.high - 1:
|
for i in proof.low ..< proof.high - 1:
|
||||||
|
@ -62,7 +62,7 @@ suite "State Endpoints - Genesis JSON Files":
|
||||||
stateNode.portalProtocol.storeContent(
|
stateNode.portalProtocol.storeContent(
|
||||||
parentContentKey,
|
parentContentKey,
|
||||||
parentContentKey.toContentId(),
|
parentContentKey.toContentId(),
|
||||||
parent.offer.toRetrievalValue().encode(),
|
parent.offer.toRetrieval().encode(),
|
||||||
)
|
)
|
||||||
|
|
||||||
proc setupCodeInDb(
|
proc setupCodeInDb(
|
||||||
|
@ -101,7 +101,7 @@ suite "State Endpoints - Genesis JSON Files":
|
||||||
# store the contract storage leaf node
|
# store the contract storage leaf node
|
||||||
let contentKey = key.toContentKey().encode()
|
let contentKey = key.toContentKey().encode()
|
||||||
stateNode.portalProtocol.storeContent(
|
stateNode.portalProtocol.storeContent(
|
||||||
contentKey, contentKey.toContentId(), offer.toRetrievalValue().encode()
|
contentKey, contentKey.toContentId(), offer.toRetrieval().encode()
|
||||||
)
|
)
|
||||||
|
|
||||||
# store the remaining contract storage nodes
|
# store the remaining contract storage nodes
|
||||||
|
@ -112,7 +112,7 @@ suite "State Endpoints - Genesis JSON Files":
|
||||||
stateNode.portalProtocol.storeContent(
|
stateNode.portalProtocol.storeContent(
|
||||||
parentContentKey,
|
parentContentKey,
|
||||||
parentContentKey.toContentId(),
|
parentContentKey.toContentId(),
|
||||||
parent.offer.toRetrievalValue().encode(),
|
parent.offer.toRetrieval().encode(),
|
||||||
)
|
)
|
||||||
|
|
||||||
for i in storageProof.low ..< storageProof.high - 1:
|
for i in storageProof.low ..< storageProof.high - 1:
|
||||||
|
@ -122,7 +122,7 @@ suite "State Endpoints - Genesis JSON Files":
|
||||||
stateNode.portalProtocol.storeContent(
|
stateNode.portalProtocol.storeContent(
|
||||||
parentContentKey,
|
parentContentKey,
|
||||||
parentContentKey.toContentId(),
|
parentContentKey.toContentId(),
|
||||||
parent.offer.toRetrievalValue().encode(),
|
parent.offer.toRetrieval().encode(),
|
||||||
)
|
)
|
||||||
|
|
||||||
asyncTest "Test getBalance, getTransactionCount, getStorageAt and getCode using JSON files":
|
asyncTest "Test getBalance, getTransactionCount, getStorageAt and getCode using JSON files":
|
||||||
|
|
|
@ -39,13 +39,13 @@ suite "State Gossip getParent - Genesis JSON Files":
|
||||||
offer = AccountTrieNodeOffer(proof: proof)
|
offer = AccountTrieNodeOffer(proof: proof)
|
||||||
|
|
||||||
var db = newMemoryDB()
|
var db = newMemoryDB()
|
||||||
db.put(key.nodeHash.data, offer.toRetrievalValue().node.asSeq())
|
db.put(key.nodeHash.data, offer.toRetrieval().node.asSeq())
|
||||||
|
|
||||||
# validate each parent offer until getting to the root node
|
# validate each parent offer until getting to the root node
|
||||||
var parent = offer.withKey(key).getParent()
|
var parent = offer.withKey(key).getParent()
|
||||||
check validateOffer(Opt.some(accountState.rootHash()), parent.key, parent.offer)
|
check validateOffer(Opt.some(accountState.rootHash()), parent.key, parent.offer)
|
||||||
.isOk()
|
.isOk()
|
||||||
db.put(parent.key.nodeHash.data, parent.offer.toRetrievalValue().node.asSeq())
|
db.put(parent.key.nodeHash.data, parent.offer.toRetrieval().node.asSeq())
|
||||||
|
|
||||||
for i in proof.low ..< proof.high - 1:
|
for i in proof.low ..< proof.high - 1:
|
||||||
parent = parent.getParent()
|
parent = parent.getParent()
|
||||||
|
@ -53,7 +53,7 @@ suite "State Gossip getParent - Genesis JSON Files":
|
||||||
Opt.some(accountState.rootHash()), parent.key, parent.offer
|
Opt.some(accountState.rootHash()), parent.key, parent.offer
|
||||||
)
|
)
|
||||||
.isOk()
|
.isOk()
|
||||||
db.put(parent.key.nodeHash.data, parent.offer.toRetrievalValue().node.asSeq())
|
db.put(parent.key.nodeHash.data, parent.offer.toRetrieval().node.asSeq())
|
||||||
|
|
||||||
# after putting all parent nodes into the trie, verify can lookup the leaf
|
# after putting all parent nodes into the trie, verify can lookup the leaf
|
||||||
let
|
let
|
||||||
|
@ -94,7 +94,7 @@ suite "State Gossip getParent - Genesis JSON Files":
|
||||||
)
|
)
|
||||||
|
|
||||||
var db = newMemoryDB()
|
var db = newMemoryDB()
|
||||||
db.put(key.nodeHash.data, offer.toRetrievalValue().node.asSeq())
|
db.put(key.nodeHash.data, offer.toRetrieval().node.asSeq())
|
||||||
|
|
||||||
# validate each parent offer until getting to the root node
|
# validate each parent offer until getting to the root node
|
||||||
var parent = offer.withKey(key).getParent()
|
var parent = offer.withKey(key).getParent()
|
||||||
|
@ -102,9 +102,7 @@ suite "State Gossip getParent - Genesis JSON Files":
|
||||||
Opt.some(accountState.rootHash()), parent.key, parent.offer
|
Opt.some(accountState.rootHash()), parent.key, parent.offer
|
||||||
)
|
)
|
||||||
.isOk()
|
.isOk()
|
||||||
db.put(
|
db.put(parent.key.nodeHash.data, parent.offer.toRetrieval().node.asSeq())
|
||||||
parent.key.nodeHash.data, parent.offer.toRetrievalValue().node.asSeq()
|
|
||||||
)
|
|
||||||
|
|
||||||
for i in storageProof.low ..< storageProof.high - 1:
|
for i in storageProof.low ..< storageProof.high - 1:
|
||||||
parent = parent.getParent()
|
parent = parent.getParent()
|
||||||
|
@ -112,9 +110,7 @@ suite "State Gossip getParent - Genesis JSON Files":
|
||||||
Opt.some(accountState.rootHash()), parent.key, parent.offer
|
Opt.some(accountState.rootHash()), parent.key, parent.offer
|
||||||
)
|
)
|
||||||
.isOk()
|
.isOk()
|
||||||
db.put(
|
db.put(parent.key.nodeHash.data, parent.offer.toRetrieval().node.asSeq())
|
||||||
parent.key.nodeHash.data, parent.offer.toRetrievalValue().node.asSeq()
|
|
||||||
)
|
|
||||||
|
|
||||||
# after putting all parent nodes into the trie, verify can lookup the leaf
|
# after putting all parent nodes into the trie, verify can lookup the leaf
|
||||||
let
|
let
|
||||||
|
|
|
@ -39,7 +39,7 @@ suite "State Gossip getParent - Test Vectors":
|
||||||
parentKey.toContentKey().encode() ==
|
parentKey.toContentKey().encode() ==
|
||||||
parentTestData.content_key.hexToSeqByte().ContentKeyByteList
|
parentTestData.content_key.hexToSeqByte().ContentKeyByteList
|
||||||
parentOffer.encode() == parentTestData.content_value_offer.hexToSeqByte()
|
parentOffer.encode() == parentTestData.content_value_offer.hexToSeqByte()
|
||||||
parentOffer.toRetrievalValue().encode() ==
|
parentOffer.toRetrieval().encode() ==
|
||||||
parentTestData.content_value_retrieval.hexToSeqByte()
|
parentTestData.content_value_retrieval.hexToSeqByte()
|
||||||
|
|
||||||
test "Check contract storage trie node parent matches expected recursive gossip":
|
test "Check contract storage trie node parent matches expected recursive gossip":
|
||||||
|
@ -68,5 +68,5 @@ suite "State Gossip getParent - Test Vectors":
|
||||||
parentKey.toContentKey().encode() ==
|
parentKey.toContentKey().encode() ==
|
||||||
parentTestData.content_key.hexToSeqByte().ContentKeyByteList
|
parentTestData.content_key.hexToSeqByte().ContentKeyByteList
|
||||||
parentOffer.encode() == parentTestData.content_value_offer.hexToSeqByte()
|
parentOffer.encode() == parentTestData.content_value_offer.hexToSeqByte()
|
||||||
parentOffer.toRetrievalValue().encode() ==
|
parentOffer.toRetrieval().encode() ==
|
||||||
parentTestData.content_value_retrieval.hexToSeqByte()
|
parentTestData.content_value_retrieval.hexToSeqByte()
|
||||||
|
|
|
@ -78,8 +78,8 @@ procSuite "State Gossip - Gossip Offer":
|
||||||
check:
|
check:
|
||||||
stateNode2.containsId(contentId)
|
stateNode2.containsId(contentId)
|
||||||
res1.isOk()
|
res1.isOk()
|
||||||
res1.get() == contentValue.toRetrievalValue()
|
res1.get() == contentValue.toRetrieval()
|
||||||
res1.get().node == contentValue.toRetrievalValue().node
|
res1.get().node == contentValue.toRetrieval().node
|
||||||
|
|
||||||
# check that the parent offer was not received by the second state instance
|
# check that the parent offer was not received by the second state instance
|
||||||
let res2 = await stateNode2.stateNetwork.getAccountTrieNode(
|
let res2 = await stateNode2.stateNetwork.getAccountTrieNode(
|
||||||
|
@ -147,8 +147,8 @@ procSuite "State Gossip - Gossip Offer":
|
||||||
check:
|
check:
|
||||||
stateNode2.containsId(contentId)
|
stateNode2.containsId(contentId)
|
||||||
res1.isOk()
|
res1.isOk()
|
||||||
res1.get() == contentValue.toRetrievalValue()
|
res1.get() == contentValue.toRetrieval()
|
||||||
res1.get().node == contentValue.toRetrievalValue().node
|
res1.get().node == contentValue.toRetrieval().node
|
||||||
|
|
||||||
# check that the offer parent was not received by the second state instance
|
# check that the offer parent was not received by the second state instance
|
||||||
let res2 = await stateNode2.stateNetwork.getContractTrieNode(
|
let res2 = await stateNode2.stateNetwork.getContractTrieNode(
|
||||||
|
@ -205,8 +205,8 @@ procSuite "State Gossip - Gossip Offer":
|
||||||
check:
|
check:
|
||||||
stateNode2.containsId(contentId)
|
stateNode2.containsId(contentId)
|
||||||
res1.isOk()
|
res1.isOk()
|
||||||
res1.get() == contentValue.toRetrievalValue()
|
res1.get() == contentValue.toRetrieval()
|
||||||
res1.get().code == contentValue.toRetrievalValue().code
|
res1.get().code == contentValue.toRetrieval().code
|
||||||
|
|
||||||
await stateNode1.stop()
|
await stateNode1.stop()
|
||||||
await stateNode2.stop()
|
await stateNode2.stop()
|
||||||
|
|
|
@ -90,8 +90,8 @@ procSuite "State Network - Offer Content":
|
||||||
check:
|
check:
|
||||||
stateNode1.containsId(contentId)
|
stateNode1.containsId(contentId)
|
||||||
getRes.isOk()
|
getRes.isOk()
|
||||||
getRes.get() == contentValue.toRetrievalValue()
|
getRes.get() == contentValue.toRetrieval()
|
||||||
getRes.get().node == contentValue.toRetrievalValue().node
|
getRes.get().node == contentValue.toRetrieval().node
|
||||||
|
|
||||||
await stateNode1.stop()
|
await stateNode1.stop()
|
||||||
|
|
||||||
|
@ -159,8 +159,8 @@ procSuite "State Network - Offer Content":
|
||||||
check:
|
check:
|
||||||
stateNode1.containsId(contentId)
|
stateNode1.containsId(contentId)
|
||||||
getRes.isOk()
|
getRes.isOk()
|
||||||
getRes.get() == contentValue.toRetrievalValue()
|
getRes.get() == contentValue.toRetrieval()
|
||||||
getRes.get().node == contentValue.toRetrievalValue().node
|
getRes.get().node == contentValue.toRetrieval().node
|
||||||
|
|
||||||
await stateNode1.stop()
|
await stateNode1.stop()
|
||||||
|
|
||||||
|
@ -227,8 +227,8 @@ procSuite "State Network - Offer Content":
|
||||||
check:
|
check:
|
||||||
stateNode1.containsId(contentId)
|
stateNode1.containsId(contentId)
|
||||||
getRes.isOk()
|
getRes.isOk()
|
||||||
getRes.get() == contentValue.toRetrievalValue()
|
getRes.get() == contentValue.toRetrieval()
|
||||||
getRes.get().code == contentValue.toRetrievalValue().code
|
getRes.get().code == contentValue.toRetrieval().code
|
||||||
|
|
||||||
await stateNode1.stop()
|
await stateNode1.stop()
|
||||||
|
|
||||||
|
@ -277,8 +277,8 @@ procSuite "State Network - Offer Content":
|
||||||
check:
|
check:
|
||||||
stateNode2.containsId(contentId)
|
stateNode2.containsId(contentId)
|
||||||
getRes.isOk()
|
getRes.isOk()
|
||||||
getRes.get() == contentValue.toRetrievalValue()
|
getRes.get() == contentValue.toRetrieval()
|
||||||
getRes.get().node == contentValue.toRetrievalValue().node
|
getRes.get().node == contentValue.toRetrieval().node
|
||||||
|
|
||||||
await stateNode1.stop()
|
await stateNode1.stop()
|
||||||
await stateNode2.stop()
|
await stateNode2.stop()
|
||||||
|
@ -327,8 +327,8 @@ procSuite "State Network - Offer Content":
|
||||||
check:
|
check:
|
||||||
stateNode2.containsId(contentId)
|
stateNode2.containsId(contentId)
|
||||||
getRes.isOk()
|
getRes.isOk()
|
||||||
getRes.get() == contentValue.toRetrievalValue()
|
getRes.get() == contentValue.toRetrieval()
|
||||||
getRes.get().node == contentValue.toRetrievalValue().node
|
getRes.get().node == contentValue.toRetrieval().node
|
||||||
|
|
||||||
await stateNode1.stop()
|
await stateNode1.stop()
|
||||||
await stateNode2.stop()
|
await stateNode2.stop()
|
||||||
|
@ -376,8 +376,8 @@ procSuite "State Network - Offer Content":
|
||||||
check:
|
check:
|
||||||
stateNode2.containsId(contentId)
|
stateNode2.containsId(contentId)
|
||||||
getRes.isOk()
|
getRes.isOk()
|
||||||
getRes.get() == contentValue.toRetrievalValue()
|
getRes.get() == contentValue.toRetrieval()
|
||||||
getRes.get().code == contentValue.toRetrievalValue().code
|
getRes.get().code == contentValue.toRetrieval().code
|
||||||
|
|
||||||
await stateNode1.stop()
|
await stateNode1.stop()
|
||||||
await stateNode2.stop()
|
await stateNode2.stop()
|
||||||
|
|
Loading…
Reference in New Issue