区块链测试驱动开发的错误
Error with Blockchain Test-Driven Development
我目前正在学习如何使用 Javascript 和 Node.js 开发区块链。我正在使用一种测试驱动的开发格式,到目前为止它非常有用。然而,不幸的是,我的一项测试不断失败,我无法查明原因。这是与此错误相关的三个代码片段;他们每个人都是一个不同的文件。为了清楚起见,第一个片段是 block.js,第二个片段是 block.test.js,第三个片段是 config.js。此外,cryptoHash 函数(在另一个文件中定义)是用于使用给定信息创建 SHA-256 哈希的函数。
const {GENESIS_DATA, MINE_RATE} = require("./config");
const cryptoHash = require("./crypto-hash");
class Block {
constructor({timestamp, lastHash, hash, data, nonce, difficulty}) {
this.timestamp = timestamp;
this.lastHash = lastHash;
this.hash = hash;
this.data = data;
this.nonce = nonce;
this.difficulty = difficulty;
}
static genesis() {
return new this(GENESIS_DATA);
}
static mineBlock({lastBlock,data}) {
let hash, timestamp;
const lastHash = lastBlock.hash;
let {difficulty} = lastBlock;
let {nonce} = 0;
do {
nonce ++;
timestamp = Date.now();
hash = cryptoHash(timestamp, lastHash, data, nonce, difficulty);
} while (hash.substring(0, difficulty) !== '0'.repeat(difficulty));
return new this({
timestamp,
lastHash,
data,
difficulty,
nonce,
hash
});
}
static adjustDifficulty({originalBlock, timestamp}) {
const {difficulty} = originalBlock;
if ((timestamp - originalBlock.timestamp) > MINE_RATE) return difficulty - 1;
return difficulty + 1;
}
}
module.exports = Block;
const Block = require('./block');
const { GENESIS_DATA, MINE_RATE } = require('./config');
const cryptoHash = require('./crypto-hash');
describe('Block', () => {
const timestamp = '2000';
const lastHash = 'foo-hash';
const hash = 'bar-hash';
const data = ['blockchain', 'data'];
const nonce = 1;
const difficulty = 1;
const block = new Block ({timestamp, lastHash, hash, data, nonce, difficulty});
it('has a timestamp, lastHash, hash, data property', () => {
expect(block.timestamp).toEqual(timestamp);
expect(block.lastHash).toEqual(lastHash);
expect(block.hash).toEqual(hash);
expect(block.data).toEqual(data);
expect(block.nonce).toEqual(nonce);
expect(block.difficulty).toEqual(difficulty);
});
describe('genesis()', () => {
const genesisBlock = Block.genesis();
it('returns a Block instance', () => {
expect(genesisBlock instanceof Block).toBe(true);
});
it('returns the genesis data', () => {
expect(genesisBlock).toEqual(GENESIS_DATA);
});
});
describe('mineBlock()', () => {
const lastBlock = Block.genesis();
const data = 'mined data';
const minedBlock = Block.mineBlock({ lastBlock, data });
it('returns a Block instance', () => {
expect(minedBlock instanceof Block).toBe(true);
});
it('sets the `lastHash` to be the `hash` of the lastBlock', () => {
expect(minedBlock.lastHash).toEqual(lastBlock.hash);
});
it('sets the `data`', () => {
expect(minedBlock.data).toEqual(data);
});
it('sets a `timestamp`', () => {
expect(minedBlock.timestamp).not.toEqual(undefined);
});
it('creates a SHA-256 `hash` based on the proper inputs', () => {
expect(minedBlock.hash).toEqual(
cryptoHash(
minedBlock.timestamp,
minedBlock.nonce,
minedBlock.difficulty,
lastBlock.hash,
data
)
);
});
it('sets a `hash` that matches the difficulty criteria', () => {
expect(minedBlock.hash.substring(0, minedBlock.difficulty))
.toEqual('0'.repeat(minedBlock.difficulty));
});
});
describe('adjustDifficulty()', () => {
it('raises the difficulty for a quickly mined block', () => {
expect(Block.adjustDifficulty({
originalBlock: block, timestamp: block.timestamp + MINE_RATE - 100
})).toEqual(block.difficulty+1);
});
it('lowers the difficulty for a slowly mined block', () => {
expect(Block.adjustDifficulty({
originalBlock: block, timestamp: block.timestamp + MINE_RATE + 100
})).toEqual(block.difficulty-1);
});
});
});
const MINE_RATE = 1000;
const INITIAL_DIFFICULTY = 1;
const GENESIS_DATA = {
timestamp: 1,
lastHash: '-----',
hash: 'hash-one',
difficulty: INITIAL_DIFFICULTY,
nonce: 0,
data: []
};
module.exports = {
GENESIS_DATA,
MINE_RATE,
};
错误是这样说的:
● 区块 › adjustDifficulty() › 提高快速开采区块的难度
expect(received).toEqual(expected)
Expected value to equal:
2
Received:
0
76 | expect(Block.adjustDifficulty({
77 | originalBlock: block, timestamp: block.timestamp + MINE_RATE - 100
> 78 | })).toEqual(block.difficulty+1);
| ^
79 | });
80 |
81 | it('lowers the difficulty for a slowly mined block', () => {
at Object.<anonymous> (block.test.js:78:15)
我知道这很多,但如果有人能帮助我,我将不胜感激 - 谢谢!
这一行...
const timestamp = '2000'; // why so stringious?
...似乎是万恶之源。看,当你创建你的测试 block
时,它的 timestamp 属性最终是一个字符串,而不是一个数字。所以这个表达式...
timestamp: block.timestamp + MINE_RATE - 100
... 给你的不是 2900
(2000 + 1000 - 100),而是 20000900
('20001000' - 100
)。您可以通过添加某种中间日志记录轻松地检查这一点。
当然,在您的其他测试中也会发生同样的情况,并且结束时间戳甚至更高(因为两个 +
都被视为 concat 操作)。但是由于存储在那里的字符串最终通过 -
操作转换为数字(尽管相当大),lowers the difficulty
测试通过得很好。
因此,直接的补救措施似乎相当简单:删除那些引号并重试。尽管如此,我还是建议至少考虑采用 TypeScript 方式 - 从长远来看 运行,利大于弊。
我目前正在学习如何使用 Javascript 和 Node.js 开发区块链。我正在使用一种测试驱动的开发格式,到目前为止它非常有用。然而,不幸的是,我的一项测试不断失败,我无法查明原因。这是与此错误相关的三个代码片段;他们每个人都是一个不同的文件。为了清楚起见,第一个片段是 block.js,第二个片段是 block.test.js,第三个片段是 config.js。此外,cryptoHash 函数(在另一个文件中定义)是用于使用给定信息创建 SHA-256 哈希的函数。
const {GENESIS_DATA, MINE_RATE} = require("./config");
const cryptoHash = require("./crypto-hash");
class Block {
constructor({timestamp, lastHash, hash, data, nonce, difficulty}) {
this.timestamp = timestamp;
this.lastHash = lastHash;
this.hash = hash;
this.data = data;
this.nonce = nonce;
this.difficulty = difficulty;
}
static genesis() {
return new this(GENESIS_DATA);
}
static mineBlock({lastBlock,data}) {
let hash, timestamp;
const lastHash = lastBlock.hash;
let {difficulty} = lastBlock;
let {nonce} = 0;
do {
nonce ++;
timestamp = Date.now();
hash = cryptoHash(timestamp, lastHash, data, nonce, difficulty);
} while (hash.substring(0, difficulty) !== '0'.repeat(difficulty));
return new this({
timestamp,
lastHash,
data,
difficulty,
nonce,
hash
});
}
static adjustDifficulty({originalBlock, timestamp}) {
const {difficulty} = originalBlock;
if ((timestamp - originalBlock.timestamp) > MINE_RATE) return difficulty - 1;
return difficulty + 1;
}
}
module.exports = Block;
const Block = require('./block');
const { GENESIS_DATA, MINE_RATE } = require('./config');
const cryptoHash = require('./crypto-hash');
describe('Block', () => {
const timestamp = '2000';
const lastHash = 'foo-hash';
const hash = 'bar-hash';
const data = ['blockchain', 'data'];
const nonce = 1;
const difficulty = 1;
const block = new Block ({timestamp, lastHash, hash, data, nonce, difficulty});
it('has a timestamp, lastHash, hash, data property', () => {
expect(block.timestamp).toEqual(timestamp);
expect(block.lastHash).toEqual(lastHash);
expect(block.hash).toEqual(hash);
expect(block.data).toEqual(data);
expect(block.nonce).toEqual(nonce);
expect(block.difficulty).toEqual(difficulty);
});
describe('genesis()', () => {
const genesisBlock = Block.genesis();
it('returns a Block instance', () => {
expect(genesisBlock instanceof Block).toBe(true);
});
it('returns the genesis data', () => {
expect(genesisBlock).toEqual(GENESIS_DATA);
});
});
describe('mineBlock()', () => {
const lastBlock = Block.genesis();
const data = 'mined data';
const minedBlock = Block.mineBlock({ lastBlock, data });
it('returns a Block instance', () => {
expect(minedBlock instanceof Block).toBe(true);
});
it('sets the `lastHash` to be the `hash` of the lastBlock', () => {
expect(minedBlock.lastHash).toEqual(lastBlock.hash);
});
it('sets the `data`', () => {
expect(minedBlock.data).toEqual(data);
});
it('sets a `timestamp`', () => {
expect(minedBlock.timestamp).not.toEqual(undefined);
});
it('creates a SHA-256 `hash` based on the proper inputs', () => {
expect(minedBlock.hash).toEqual(
cryptoHash(
minedBlock.timestamp,
minedBlock.nonce,
minedBlock.difficulty,
lastBlock.hash,
data
)
);
});
it('sets a `hash` that matches the difficulty criteria', () => {
expect(minedBlock.hash.substring(0, minedBlock.difficulty))
.toEqual('0'.repeat(minedBlock.difficulty));
});
});
describe('adjustDifficulty()', () => {
it('raises the difficulty for a quickly mined block', () => {
expect(Block.adjustDifficulty({
originalBlock: block, timestamp: block.timestamp + MINE_RATE - 100
})).toEqual(block.difficulty+1);
});
it('lowers the difficulty for a slowly mined block', () => {
expect(Block.adjustDifficulty({
originalBlock: block, timestamp: block.timestamp + MINE_RATE + 100
})).toEqual(block.difficulty-1);
});
});
});
const MINE_RATE = 1000;
const INITIAL_DIFFICULTY = 1;
const GENESIS_DATA = {
timestamp: 1,
lastHash: '-----',
hash: 'hash-one',
difficulty: INITIAL_DIFFICULTY,
nonce: 0,
data: []
};
module.exports = {
GENESIS_DATA,
MINE_RATE,
};
错误是这样说的:
● 区块 › adjustDifficulty() › 提高快速开采区块的难度
expect(received).toEqual(expected)
Expected value to equal:
2
Received:
0
76 | expect(Block.adjustDifficulty({
77 | originalBlock: block, timestamp: block.timestamp + MINE_RATE - 100
> 78 | })).toEqual(block.difficulty+1);
| ^
79 | });
80 |
81 | it('lowers the difficulty for a slowly mined block', () => {
at Object.<anonymous> (block.test.js:78:15)
我知道这很多,但如果有人能帮助我,我将不胜感激 - 谢谢!
这一行...
const timestamp = '2000'; // why so stringious?
...似乎是万恶之源。看,当你创建你的测试 block
时,它的 timestamp 属性最终是一个字符串,而不是一个数字。所以这个表达式...
timestamp: block.timestamp + MINE_RATE - 100
... 给你的不是 2900
(2000 + 1000 - 100),而是 20000900
('20001000' - 100
)。您可以通过添加某种中间日志记录轻松地检查这一点。
当然,在您的其他测试中也会发生同样的情况,并且结束时间戳甚至更高(因为两个 +
都被视为 concat 操作)。但是由于存储在那里的字符串最终通过 -
操作转换为数字(尽管相当大),lowers the difficulty
测试通过得很好。
因此,直接的补救措施似乎相当简单:删除那些引号并重试。尽管如此,我还是建议至少考虑采用 TypeScript 方式 - 从长远来看 运行,利大于弊。