Created
December 29, 2011 16:35
-
-
Save justmoon/1534875 to your computer and use it in GitHub Desktop.
BlockChain, main processing sequence, Step example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Connect a block and store it. | |
* | |
* This function takes over once add() has ascertained that the block passed | |
* intrinsic checks and there is no reorg currently in progress. | |
*/ | |
var processBlock = this.processBlock = function processBlock(bw) { | |
// Shorthand | |
var block = bw.block; | |
Step( | |
function prepare() { | |
isProcessing = true; | |
// Index block while it is being connected | |
connectingBlockIndex.add(bw); | |
lastRecvBlock = block; | |
// See if any orphans were waiting for this block | |
var childBws = connectingBlockIndex.getByParent(bw.hash64); | |
if (childBws) { | |
// Remove those orphans as chain heads and add us instead | |
connectingBlockIndex.removeHeads(childBws); | |
connectingBlockIndex.addHead(bw, bw.parent64); | |
// This will cause our children to be added once we are processed | |
bw.children = childBws; | |
} | |
this(null); | |
}, | |
function connect(err) { | |
if (err) throw err; | |
connectBlock(bw, this); | |
}, | |
function verifyConnection(err) { | |
if (err) throw err; | |
bw.parent.verifyChild(self, bw.block, this); | |
}, | |
function applyParent(err) { | |
if (err) throw err; | |
switch (bw.mode) { | |
case 'main': | |
connectToMainChain(bw, this); | |
break; | |
case 'side': | |
connectToSideChain(bw, bw.parent, this); | |
break; | |
} | |
}, | |
function prepareTxs(err) { | |
if (err) throw err; | |
var txList = []; | |
bw.txs = bw.txs.map(function (tx) { | |
if (!(tx instanceof Transaction)) { | |
tx = new Transaction(tx); | |
} | |
// Calculate the hash | |
tx.getHash(); | |
txList.push(tx.hash); | |
return tx; | |
}); | |
bw.block.txs = txList; | |
this(null); | |
}, | |
function verifyBlockStep(err) { | |
if (err) throw err; | |
verifyBlock(bw, this); | |
}, | |
function reorganize(err) { | |
if (err) throw err; | |
if (bw.mode == "side" && bw.block.moreWorkThan(currentTopBlock)) { | |
self.reorganize(currentTopBlock, bw.block, this); | |
} else { | |
this(null); | |
} | |
}, | |
function saveTransactions(err) { | |
if (err) throw err; | |
self.saveTransactions(bw.block, bw.txs, this); | |
}, | |
function saveBlock(err) { | |
if (err) throw err; | |
self.saveBlock(bw, this); | |
}, | |
function connectTransactions(err) { | |
if (err) throw err; | |
if (bw.mode == "main") { | |
self.connectTransactions(bw.block, bw.txs, this); | |
} else { | |
this(); | |
} | |
}, | |
function queueDependents(err) { | |
if (err) throw err; | |
// Children of this block can now be processed as well | |
// TODO: In case this block failed to be added, we should discard | |
// its children as well. | |
if (bw.children) { | |
bw.children.forEach(function (childBw) { | |
childBw.block.attachTo(bw.block); | |
}); | |
if (bw.mode == "main") { | |
// Main chain blocks are processed with priority | |
incomingBlockQueue = bw.children.concat(incomingBlockQueue); | |
} else { | |
// Side chain blocks are processed last | |
incomingBlockQueue = incomingBlockQueue.concat(bw.children); | |
} | |
} | |
this(); | |
}, | |
function finalize(err) { | |
// The codes "orphan" and "discard" are special error codes used to | |
// skip to this point. | |
if (err === "orphan" || err === "discard") { | |
err = null; | |
} | |
// If block failed processing, remove from caches | |
if (err) { | |
// If this block was connected to the main chain, we need to undo | |
// the updating of currentTopBlock | |
if (bw.mode == "main") { | |
currentTopBlock = bw.parent; | |
} | |
connectingBlockIndex.remove(bw); | |
recentBlockIndex.remove(bw.hash64); | |
} | |
bw.callback(err); | |
bw = null; | |
if (incomingBlockQueue.length) { | |
var next = incomingBlockQueue.shift(); | |
process.nextTick(self.processBlock.bind(self, next)); | |
//self.processBlock(next); | |
} else { | |
isProcessing = false; | |
self.emit('queueDone', {chain: self}); | |
} | |
} | |
); | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment