Skip to content

Commit

Permalink
Fluffy state network fixes and improvements (#2576)
Browse files Browse the repository at this point in the history
* Cleanup tests.

* Improve offer sort function in state bridge.

* Verify nibble prefix for leaf and extension nodes during lookup.
  • Loading branch information
bhartnett authored Aug 23, 2024
1 parent dbabe7e commit 507a9e7
Show file tree
Hide file tree
Showing 8 changed files with 37 additions and 24 deletions.
22 changes: 18 additions & 4 deletions fluffy/network/state/state_endpoints.nim
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,16 @@ proc getNextNodeHash(
)

# leaf or extension node
let (_, isLeaf, prefix) = decodePrefix(trieNodeRlp.listElem(0))
let
(_, isLeaf, prefix) = decodePrefix(trieNodeRlp.listElem(0))
unpackedPrefix = prefix.unpackNibbles()

if unpackedPrefix != nibbles[nibbleIdx ..< nibbleIdx + unpackedPrefix.len()]:
# The nibbles don't match so we stop the search and don't increment
# the nibble index to indicate how many nibbles were consumed
return Opt.none((Nibbles, NodeHash))

nibbleIdx += prefix.unpackNibbles().len()
if isLeaf:
return Opt.none((Nibbles, NodeHash))

Expand All @@ -59,7 +68,6 @@ proc getNextNodeHash(
if nextHashBytes.len() == 0:
return Opt.none((Nibbles, NodeHash))

nibbleIdx += prefix.unpackNibbles().len()
Opt.some(
(nibbles[0 ..< nibbleIdx].packNibbles(), KeccakHash.fromBytes(nextHashBytes))
)
Expand Down Expand Up @@ -91,7 +99,10 @@ proc getAccountProof(

key = AccountTrieNodeKey.init(nextPath, nextNodeHash)

Opt.some(proof)
if nibblesIdx < nibbles.len():
Opt.none(TrieProof)
else:
Opt.some(proof)

proc getStorageProof(
n: StateNetwork, storageRoot: KeccakHash, address: EthAddress, storageKey: UInt256
Expand Down Expand Up @@ -119,7 +130,10 @@ proc getStorageProof(

key = ContractTrieNodeKey.init(addressHash, nextPath, nextNodeHash)

Opt.some(proof)
if nibblesIdx < nibbles.len():
Opt.none(TrieProof)
else:
Opt.some(proof)

proc getAccount(
n: StateNetwork, blockHash: BlockHash, address: EthAddress
Expand Down
4 changes: 2 additions & 2 deletions fluffy/network/state/state_utils.nim
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,12 @@ func rlpDecodeContractTrieNode*(contractTrieNode: TrieNode): Result[UInt256, str
err(e.msg)

func toAccount*(accountProof: TrieProof): Result[Account, string] {.inline.} =
doAssert(accountProof.len() > 1)
doAssert(accountProof.len() > 0)

rlpDecodeAccountTrieNode(accountProof[^1])

func toSlot*(storageProof: TrieProof): Result[UInt256, string] {.inline.} =
doAssert(storageProof.len() > 1)
doAssert(storageProof.len() > 0)

rlpDecodeContractTrieNode(storageProof[^1])

Expand Down
17 changes: 8 additions & 9 deletions fluffy/tests/state_network_tests/state_test_helpers.nim
Original file line number Diff line number Diff line change
Expand Up @@ -77,20 +77,21 @@ proc getGenesisAlloc*(filePath: string): GenesisAlloc =

proc toState*(
alloc: GenesisAlloc
): (HexaryTrie, Table[EthAddress, HexaryTrie]) {.raises: [RlpError].} =
): (HexaryTrie, TableRef[EthAddress, HexaryTrie]) {.raises: [RlpError].} =
var accountTrie = initHexaryTrie(newMemoryDB())
var storageStates = Table[EthAddress, HexaryTrie]()
let storageStates = TableRef[EthAddress, HexaryTrie]()

for address, genAccount in alloc:
var storageRoot = EMPTY_ROOT_HASH
var codeHash = EMPTY_CODE_HASH
var
storageRoot = EMPTY_ROOT_HASH
codeHash = EMPTY_CODE_HASH

if genAccount.code.len() > 0:
var storageTrie = initHexaryTrie(newMemoryDB())
for slotKey, slotValue in genAccount.storage:
let key = keccakHash(toBytesBE(slotKey)).data
let value = rlp.encode(slotValue)
storageTrie.put(key, value)
storageTrie.put(key, rlp.encode(slotValue))

storageStates[address] = storageTrie
storageRoot = storageTrie.rootHash()
codeHash = keccakHash(genAccount.code)
Expand All @@ -101,9 +102,7 @@ proc toState*(
storageRoot: storageRoot,
codeHash: codeHash,
)
let key = keccakHash(address).data
let value = rlp.encode(account)
accountTrie.put(key, value)
accountTrie.put(keccakHash(address).data, rlp.encode(account))

(accountTrie, storageStates)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,6 @@ suite "State Endpoints - Genesis JSON Files":
let
storageProof = storageState.generateStorageProof(slotKey)
leafNode = storageProof[^1]
slotKeyHash = keccakHash(toBytesBE(slotKey)).data
path = removeLeafKeyEndNibbles(
Nibbles.init(keccakHash(toBytesBE(slotKey)).data, true), leafNode
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ procSuite "State Endpoints":
leafData = testData
contentKeyBytes = leafData.content_key.hexToSeqByte().ContentKeyByteList
contentKey = ContentKey.decode(contentKeyBytes).get()
contentId = toContentId(contentKeyBytes)
contentValueBytes = leafData.content_value_offer.hexToSeqByte()
contentValue = AccountTrieNodeOffer.decode(contentValueBytes).get()

Expand Down Expand Up @@ -163,7 +162,6 @@ procSuite "State Endpoints":
leafData = testData
contentKeyBytes = leafData.content_key.hexToSeqByte().ContentKeyByteList
contentKey = ContentKey.decode(contentKeyBytes).get()
contentId = toContentId(contentKeyBytes)
contentValueBytes = leafData.content_value_offer.hexToSeqByte()
contentValue = AccountTrieNodeOffer.decode(contentValueBytes).get()

Expand Down Expand Up @@ -192,7 +190,6 @@ procSuite "State Endpoints":
leafData = testData
contentKeyBytes = leafData.content_key.hexToSeqByte().ContentKeyByteList
contentKey = ContentKey.decode(contentKeyBytes).get()
contentId = toContentId(contentKeyBytes)
contentValueBytes = leafData.content_value_offer.hexToSeqByte()
contentValue = ContractTrieNodeOffer.decode(contentValueBytes).get()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@ procSuite "State Gossip - Gossip Offer":
parentContentKey = ContentKey.decode(parentContentKeyBytes).get()
parentContentId = toContentId(parentContentKeyBytes)
parentContentValueBytes = parentTestData.content_value_offer.hexToSeqByte()
parentContentValue = AccountTrieNodeOffer.decode(parentContentValueBytes).get()

# set valid state root
stateNode1.mockBlockHashToStateRoot(contentValue.blockHash, stateRoot)
Expand Down Expand Up @@ -133,7 +132,6 @@ procSuite "State Gossip - Gossip Offer":
parentContentKey = ContentKey.decode(parentContentKeyBytes).get()
parentContentId = toContentId(parentContentKeyBytes)
parentContentValueBytes = parentTestData.content_value_offer.hexToSeqByte()
parentContentValue = ContractTrieNodeOffer.decode(parentContentValueBytes).get()

# set valid state root
stateNode1.mockBlockHashToStateRoot(contentValue.blockHash, stateRoot)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import
template checkValidProofsForExistingLeafs(
genAccounts: GenesisAlloc,
accountState: HexaryTrie,
storageStates: Table[EthAddress, HexaryTrie],
storageStates: TableRef[EthAddress, HexaryTrie],
) =
for address, account in genAccounts:
var acc = newAccount(account.nonce, account.balance)
Expand Down Expand Up @@ -74,7 +74,7 @@ template checkValidProofsForExistingLeafs(
template checkInvalidProofsWithBadValue(
genAccounts: GenesisAlloc,
accountState: HexaryTrie,
storageStates: Table[EthAddress, HexaryTrie],
storageStates: TableRef[EthAddress, HexaryTrie],
) =
for address, account in genAccounts:
var acc = newAccount(account.nonce, account.balance)
Expand Down
8 changes: 7 additions & 1 deletion fluffy/tools/portal_bridge/portal_bridge_state.nim
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,13 @@ proc runBackfillGossipBlockOffersLoop(
yId = ContentKeyByteList.init(y[0]).toContentId()
xDistance = portalNodeId xor xId
yDistance = portalNodeId xor yId
if xDistance >= yDistance: 1 else: -1

if xDistance == yDistance:
0
elif xDistance > yDistance:
1
else:
-1

# Sort the offers based on the distance from the node so that we will gossip
# content that is closest to the node first
Expand Down

0 comments on commit 507a9e7

Please sign in to comment.