Skip to content

Commit

Permalink
Merge PR # 1110 from 'masterchief164/update_IBD'
Browse files Browse the repository at this point in the history
  • Loading branch information
pinheadmz committed Jan 26, 2023
2 parents 615a6d9 + f271412 commit 57f5956
Show file tree
Hide file tree
Showing 4 changed files with 266 additions and 4 deletions.
20 changes: 16 additions & 4 deletions lib/blockchain/chain.js
Original file line number Diff line number Diff line change
Expand Up @@ -2035,10 +2035,22 @@ class Chain extends AsyncEmitter {
*/

getProgress() {
const start = this.network.genesis.time;
const current = this.tip.time - start;
const end = util.now() - start - 40 * 60;
return Math.min(1, current / end);
const time = util.now();

const currentCount = this.db.state.tx;
const currentTime = this.tip.time;

const lastCount = this.network.txnData.count;
const lastTime = this.network.txnData.time;
const rate = this.network.txnData.rate;

let total;
if (currentCount <= lastCount)
total = lastCount + (time - lastTime) * rate;
else
total = currentCount + (time - currentTime) * rate;

return Math.min(currentCount / total, 1);
}

/**
Expand Down
1 change: 1 addition & 0 deletions lib/protocol/network.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ class Network {
this.port = options.port;
this.checkpointMap = options.checkpointMap;
this.lastCheckpoint = options.lastCheckpoint;
this.txnData = options.txnData;
this.checkpoints = [];
this.halvingInterval = options.halvingInterval;
this.genesis = options.genesis;
Expand Down
24 changes: 24 additions & 0 deletions lib/protocol/networks.js
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,12 @@ main.checkpointMap = {

main.lastCheckpoint = 525000;

main.txnData = {
rate: 2.925802860942233,
time: 1661697692,
count: 760120522
};

/**
* @const {Number}
* @default
Expand Down Expand Up @@ -559,6 +565,12 @@ testnet.checkpointMap = {

testnet.lastCheckpoint = 1050000;

testnet.txnData = {
rate: 0.1079119341520164,
time: 1661705221,
count: 63531852
};

testnet.halvingInterval = 210000;

testnet.genesis = {
Expand Down Expand Up @@ -722,6 +734,12 @@ regtest.port = 48444;
regtest.checkpointMap = {};
regtest.lastCheckpoint = 0;

regtest.txnData = {
rate: 0,
time: 0,
count: 0
};

regtest.halvingInterval = 150;

regtest.genesis = {
Expand Down Expand Up @@ -885,6 +903,12 @@ simnet.checkpointMap = {};

simnet.lastCheckpoint = 0;

simnet.txnData = {
time: 0,
count: 0,
rate: 0
};

simnet.halvingInterval = 210000;

simnet.genesis = {
Expand Down
225 changes: 225 additions & 0 deletions test/chain-progress-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,225 @@
/* eslint-env mocha */
/* eslint prefer-arrow-callback: "off" */

'use strict';

const assert = require('bsert');
const Network = require('../lib/protocol/network');
const consensus = require('../lib/protocol/consensus');
const Chain = require('../lib/blockchain/chain');
const BlockStore = require('../lib/blockstore/level');
const Miner = require('../lib/mining/miner');
const util = require('../lib/utils/util');
const MemWallet = require('./util/memwallet');

const network = Network.get('regtest');
const savedBip16Time = consensus.BIP16_TIME;
const savedUtilNow = util.now;

const blocks = new BlockStore({
memory: true,
network
});

const chain = new Chain({
memory: true,
blocks,
network
});

const miner = new Miner({
chain
});

const wallet = new MemWallet({
network,
witness: true
});

const address = wallet.getReceive();

async function mineBlocks(n) {
const entries = [];
for (let i = 0; i < n; i++) {
const job = await miner.cpu.createJob();
// Mine blocks all ten minutes apart from regtest genesis
job.attempt.time = chain.tip.time + (60 * 10);
const block = await job.mineAsync();
const entry = await chain.add(block);
wallet.addBlock(entry, block.txs);
entries.push(entry);
}
return entries;
}

async function mineBlockWithMTXs(mtxs) {
const job = await miner.cpu.createJob();
for (const mtx of mtxs)
job.addTX(mtx.toTX(), mtx.view);
job.refresh();
job.attempt.time = chain.tip.time + (60 * 10);
const block = await job.mineAsync();
const entry = await chain.add(block);
wallet.addBlock(entry, block.txs);
return entry;
}

describe('Chain Sync Progress', function () {
before(async () => {
await blocks.open();
await chain.open();
await miner.open();

miner.addresses.length = 0;
miner.addAddress(address);

// regtest genesis timestamp ordinarily pre-dates P2SH
consensus.BIP16_TIME = 0;
});

after(async () => {
await miner.close();
await chain.close();
await blocks.close();

// restore
consensus.BIP16_TIME = savedBip16Time;
util.now = savedUtilNow;
network.txnData = {
rate: 0,
time: 0,
count: 0
};
});

it('should generate 100 blocks with 1 tx each (coinbase only)', async () => {
await mineBlocks(100);

// Imagine releasing software at this point using these data
network.txnData = {
count: 101,
time: chain.tip.time,
rate: 1 / 600 // tx per second (one per ten minute block)
};
});

it('should generate 100 blocks with 2 tx each', async () => {
for (let i = 0; i < 100; i++) {
const mtx = await wallet.create({
outputs: [{
address: wallet.getAddress(),
value: 1e8
}]
});
await mineBlockWithMTXs([mtx]);
}
});

it('should generate 100 blocks with 3 tx each', async () => {
for (let i = 0; i < 100; i++) {
const mtx1 = await wallet.create({
outputs: [{
address: wallet.getAddress(),
value: 1e8
}]
});
// prevent double spend
wallet.addTX(mtx1.toTX());
const mtx2 = await wallet.create({
outputs: [{
address: wallet.getAddress(),
value: 1e8
}]
});
await mineBlockWithMTXs([mtx1, mtx2]);
}
});

it('should have expected chain state', async () => {
assert.strictEqual(chain.height, 300);
assert.strictEqual(chain.db.state.tx, (1 + 100 + 200 + 300));
});

describe('New chain', function () {
// time never changes
util.now = () => {
return chain.tip.time;
};

const newBlocks = new BlockStore({
memory: true,
network
});

const newChain = new Chain({
memory: true,
blocks,
network
});

before(async () => {
await newBlocks.open();
await newChain.open();
});

after(async () => {
await newChain.close();
await newBlocks.close();
});

it('should sync the first 100 blocks and get progress', async () => {
for (let i = 1; i <= 100; i++) {
const entry = await chain.getEntry(i);
const block = await chain.getBlock(entry.hash);
await newChain.add(block);
}

const percent = parseInt(newChain.getProgress() * 100);
// Only 100 out of 600 total txs have been processed
// but at this point all we know about the chain is the
// hard-coded values. We assume the tx rate of one per ten minutes
// continues until the current time, which turns out to be wrong.
// The current guess is 100 down out of (we think) 300 total.
assert.strictEqual(percent, 33);
});

it('should sync the next 100 blocks and get progress', async () => {
for (let i = 101; i <= 200; i++) {
const entry = await chain.getEntry(i);
const block = await chain.getBlock(entry.hash);
await newChain.add(block);
}

const percent = parseInt(newChain.getProgress() * 100);
// Even though we have observed the tx rate on chain double
// over the last 100 blocks, we continue to use the 1 tx per ten minutes
// rate to predict the future from this point forward.
// The new guess is 300 down out of (we think) 400 total.
assert.strictEqual(percent, 75);
});

it('should sync the next 99 blocks and approach 100%', async () => {
for (let i = 201; i < 300; i++) {
const entry = await chain.getEntry(i);
const block = await chain.getBlock(entry.hash);
await newChain.add(block);
}

const percent = parseInt(newChain.getProgress() * 100);
// As we approach the current time the actual tx count gets closer and
// closer to accurate and the amount of future txs we need to predict
// drops to almost zero.
// The new guess is essentially 599 down out of (we think) 600 total.
assert.strictEqual(percent, 99);
});

it('should sync the last block and reach 100%', async () => {
const entry = await chain.getEntry(300);
const block = await chain.getBlock(entry.hash);
await newChain.add(block);

const percent = parseInt(newChain.getProgress() * 100);
assert.strictEqual(percent, 100);
});
});
});

0 comments on commit 57f5956

Please sign in to comment.