Reorg Scanner : Deep Reorg #21
wankhede04
started this conversation in
Ideas
Replies: 1 comment
-
This is the updated code for DAG approach:type BlockNode struct {
Height uint64
Hash uint64
ParentHash uint64
Children []*BlockNode
}
func (c *NodeClient) findDeepReorgsInternally1(ctx context.Context,
template *template.Template,
rc *RemoteCursor,
) map[uint64]map[uint64]uint64 {
// mapping to store information of blocks on particular height
deepReorgs := make(map[uint64][]*BlockNode)
// store key and value fetched from DB
var k []byte
var v []byte
var err error
// stores maximum block height in order to find main chain
var max uint64 = 0
// store block-height, block-hash, and block's parent hash
var height, hash, parentHash uint64
// mapping to store block information corresponding to their block hash
blocks := make(map[uint64]*BlockNode)
// bool to avoid adding 1st node as children to a nil node
var isFirst = true
// loop to iterate over all blocks as key value pairs and store their info
for k, v, err = rc.Next(); err == nil && k != nil; k, v, err = rc.Next() {
// fetch block height, hash, and parentHash from key vlaue pair
height = binary.BigEndian.Uint64(k[:8])
hash = binary.BigEndian.Uint64(k[8:40])
parentHash = binary.BigEndian.Uint64(v[4:36])
// initialize new block info
newNode := &BlockNode{
Height: height,
Hash: hash,
ParentHash: parentHash,
Children: []*BlockNode{},
}
// map block info corresponding to its hash
blocks[hash] = newNode
// condition to append block info to existing blockInfos according to their block height
if _, found := deepReorgs[height]; found {
// add block address as its parent's children
blocks[newNode.ParentHash].Children = append(blocks[newNode.ParentHash].Children, newNode)
deepReorgs[height] = append(deepReorgs[height], newNode)
} else {
if isFirst {
isFirst = false
} else {
// add block address as its parent's children
blocks[newNode.ParentHash].Children = append(blocks[newNode.ParentHash].Children, newNode)
}
deepReorgs[height] = []*BlockNode{newNode}
}
// helps in finding longest chain
if height > max {
max = height
}
}
// returns empty mapping when no block info is available
if len(blocks) == 0 {
return make(map[uint64]map[uint64]uint64)
}
// block to iterate over to find main chain
var node *BlockNode
var found bool = true
// mapping to store main block corresponding to its height
mainChain := make(map[uint64]*BlockNode)
// maps main block according to its height
for node = deepReorgs[max][0]; found; node, found = blocks[node.ParentHash] {
mainChain[node.Height] = node
}
// mapping to store info for blockHeight of block from which reorgs are originating -> length of reorgs -> number of reorgs of corresponding length
allReorgs := make(map[uint64]map[uint64]uint64)
for _, node := range mainChain {
// only iterate when there is a reorg initiating from that block
if len(node.Children) > 1 {
// initialize mapping for a particular node height
allReorgs[node.Height] = make(map[uint64]uint64)
// iterate over child blocks of node with reorg chains
for _, block := range node.Children {
// only iterate if it is not a part of main chain
if mainChain[block.Height].Hash != block.Hash {
allReorgs = appendDeepReorgInfo(1, block, allReorgs, node.Height)
}
}
}
}
return allReorgs
}
// function to be called upon finding reorgs to store number of reorgs on that height corresponding to that reorg height
func appendDeepReorgInfo(reorgHeight uint64, node *BlockNode, allReorgs map[uint64]map[uint64]uint64, nodeHeight uint64) map[uint64]map[uint64]uint64 {
// reorg count to be incremented only when node is a leaf node
if len(node.Children) == 0 {
// increment reorg count for that reorg height reorg height
allReorgs[nodeHeight][reorgHeight]++
} else {
// iterate over all other blocks to find reorgs of increased length
for _, block := range node.Children {
appendDeepReorgInfo(reorgHeight+1, block, allReorgs, nodeHeight)
}
}
return allReorgs
} The allReorgs map, contains information about reorganizations at different heights and their lengths. In summary, this function analyzes the blocks in a blockchain to identify deep reorganizations. It constructs a map to represent the main chain and another map to store information about reorganizations at different heights and their lengths. |
Beta Was this translation helpful? Give feedback.
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
Background
The current reorg scanner is fairly simplistic and lacks the ability to handle "deep" reorgs that extend beyond a single block. In scenarios like these, it merely displays each consecutive block number as partaking in a reorg. Enhancements to this tool could include the ability to consolidate these into grouped deep reorgs, as well as possibly showcasing instances where multiple branches exist at each reorg junction.
Current implimentation of the reorg sanner
The current scanner works by going through the "Header" table, which stores information about each block. Each entry in the table includes the block number and the block hash. The scanner looks for entries with the same block number but different hashes, which signify a reorg.
Here's a simplified breakdown of the code :
Approach towards scanning deep reorg
Here's a high level idea towards how we can approach this
Iteration 1 : Identifying deep reorgs
To modify this existing code to scan for deep reorgs, we need to keep track of consecutive block numbers that are part of the same reorg. Additionally, we need to store not just a single block hash for each block number in the set map, but all block hashes for that block number.
Here's a modification of the
findReorgsInternally
function:Now the deepReorgs slice will contain the block numbers of deep reorgs.
Note that int this case block numbers will be repeated if they are part of different deep reorgs.
Limitations of the above approach (iteration 1)
The above approach for identifying deep reorgs does not distinguish between deep reorgs and their respective forks.
The code provided detects deep reorgs by identifying when there is a change in the block hash for the same block number over consecutive blocks. However, it does not track the different branches that might be created during a fork.
Iteration 2 : Identifying deep reorgs and branches
When a reorg occurs, the parent hash of the new blocks will not match the hash of the previous block at the same height. By keeping track of parent-child relationships between blocks, we can determine when a reorg has occurred and also trace the separate branches of the blockchain.
Here's how the code for identifying branches would look like
The deepReorgs map, represents a sort of "inverted" tree or forest structure where each key is associated with multiple values (hashes of blocks and their parents)
This data structure can help us keep track of all the different versions of a block.
Iteration 3 : Representing the Reorgs as a DAG
Creating a DAG to represent a blockchain, including reorganizations, involves structuring each block as a node and each parent-child relationship between blocks as a directed edge. We will be maintaining a DAG where each block points to its parent block, and forks in the blockchain are represented as nodes in the DAG with more than one child.
Each block is represented as a node in a Directed Acyclic Graph (DAG). Each node points to its parent node, and also contains a list of its children nodes, representing blocks that are directly built upon it. A reorganization (or a fork in the blockchain) is represented as a node with more than one child.
Beta Was this translation helpful? Give feedback.
All reactions