我有以下 javascript 脚本。我正在尝试为区 block 链的工作原理构建一个示例脚本。我将所有 block 数据存储在级别数据库中。
const SHA256 = require('crypto-js/sha256');
var levelDB = require('./levelSandbox');
class Block{
constructor(data){
this.hash = "",
this.height = 0,
this.body = data,
this.time = 0,
this.previousBlockHash = ""
}
}
class Blockchain{
constructor(levelDB){
this.levelDB = levelDB;
this.blocksInLevelDB = {};
this.chain = {};
this.getBlockHeight()
.then(height => {
if(!height){
this.addBlock(new Block("First block in the chain - Genesis block"));
}
})
}
// Method for adding new block
addBlock(newBlock){
this.getBlockHeight()
.then(height => {
console.log('block height is: ', height);
console.log('blocksInLevelDB: ', this.blocksInLevelDB);
// Set block hight
newBlock.height = height;
// Set UTC timestamp
newBlock.time = new Date().getTime().toString().slice(0,-3);
// Set previous block hash
if(height > 0){
let blockData = JSON.parse(this.blocksInLevelDB[height-1]);
newBlock.previousBlockHash = blockData.hash;
}
// Block hash with SHA256 using newBlock and converting to a string
newBlock.hash = SHA256(JSON.stringify(newBlock)).toString();
console.log('newBlock obj: ',newBlock);
// Adding block object to chain & save in level db
this.levelDB.addLevelDBData(height, JSON.stringify(newBlock))
.then(console.log('Block added to level db'))
.catch(function(err){console.log('Error in adding new block: ', err)})
})
}
// Get block height
getBlockHeight(){
return this.levelDB.getAllDataFromLevelDB()
.then(data => {
let blockHeight = data.length;
for (const elem of data){
this.blocksInLevelDB[elem.key] = elem.value;
}
return blockHeight;
})
.catch(function(err){
return err;
});
}
}
正常情况下一切正常,除了一些情况,比如 -
案例.1 - 当级别 DB 没有数据(空)时,如果我运行以下代码,则只有一条记录插入到级别 DB,而不是两条。
var blockChain = new Blockchain(levelDB);
blockChain.addBlock(new Block('Second block in the chain'));
但是,如果我像这样修改上面的代码 -
var blockChain = new Blockchain(levelDB);
setTimeout(function(){
blockChain.addBlock(new Block('Second block in the chain'));
}, 3000);
然后它工作正常(插入两条记录)。
案例.2 - 当 Level DB 有不止一条记录时 & 如果我尝试添加一条记录,它工作正常。例如。
var blockChain = new Blockchain(levelDB);
blockChain.addBlock(new Block('Third block in the chain'));
但是当我尝试添加多条记录时,只有一条记录被插入(最后一条)。例如。
var blockChain = new Blockchain(levelDB);
blockChain.addBlock(new Block('Third block in the chain'));
blockChain.addBlock(new Block('Fourth block in the chain'));
blockChain.addBlock(new Block('Fifth block in the chain'));
我知道这是因为我对 getBlockHeight()
的所有调用都异步执行并获得相同数量的记录(区 block 链高度)的 promise (异步性质)。因此,在添加新 block 时,所有记录都使用相同的键插入并相互覆盖。但是,无法理解处理这种情况的正确方法是什么。
最佳答案
好的,这是粗略的执行顺序:
new Blockchain(levelDB);
this.levelDB = levelDB; // constructor
this.blocksInLevelDB = {}; // constructor
this.chain = {}; // constructor
this.getBlockHeight() // ASYNC, constructor
| blockChain.addBlock(new Block('Second block in the chain'));
| this.getBlockHeight() // ASYNC, called by ^
| |
L----+--- if (!height) // true
| this.addBlock(new Block("First blo..
| this.getBlockHeight() // ASYNC
| |
L--- +---> ... this.levelDB.addLevelDBData(height, ...) // ASYNC
| // ^ second block is added, at height 0
|
L---> ... this.levelDB.addLevelDBData(height, ...)
// ^ first block is added, again at height 0
为避免这种情况,您可能也应该为您的 BlockChain 类使用异步模式。
类似于:
let blockChain = new BlockChain(levelDB);
blockChain.init()
.then(() =>
blockChain.addBlock(
new Block('Second block in the chain')))
.catch(...);
为此,您需要定义一个 init()
方法来检查高度、插入第一个 block 并返回一个 Promise
。
关于javascript - 如何处理这种 JavaScript Promise 相关情况?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53580485/