Skip to content

Commit 6009504

Browse files
authored
Merge pull request #749 from ainblockchain/release/v0.9.3
Merge Release/v0.9.3 into master branch
2 parents df6ffd8 + e6f475e commit 6009504

File tree

181 files changed

+17476
-7853
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

181 files changed

+17476
-7853
lines changed

README.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -97,9 +97,9 @@ yarn install
9797
```
9898
- Run blockchain nodes
9999
```
100-
MIN_NUM_VALIDATORS=3 ACCOUNT_INDEX=0 DEBUG=false STAKE=100000 CONSOLE_LOG=true ENABLE_DEV_SET_CLIENT_API=true ENABLE_GAS_FEE_WORKAROUND=true node client/index.js
101-
MIN_NUM_VALIDATORS=3 ACCOUNT_INDEX=1 DEBUG=false STAKE=100000 CONSOLE_LOG=true ENABLE_DEV_SET_CLIENT_API=true ENABLE_GAS_FEE_WORKAROUND=true node client/index.js
102-
MIN_NUM_VALIDATORS=3 ACCOUNT_INDEX=2 DEBUG=false STAKE=100000 CONSOLE_LOG=true ENABLE_DEV_SET_CLIENT_API=true ENABLE_GAS_FEE_WORKAROUND=true node client/index.js
100+
ACCOUNT_INDEX=0 PEER_CANDIDATE_JSON_RPC_URL='' DEBUG=false STAKE=100000 CONSOLE_LOG=true ENABLE_DEV_CLIENT_SET_API=true ENABLE_GAS_FEE_WORKAROUND=true node client/index.js
101+
ACCOUNT_INDEX=1 DEBUG=false STAKE=100000 CONSOLE_LOG=true ENABLE_DEV_CLIENT_SET_API=true ENABLE_GAS_FEE_WORKAROUND=true node client/index.js
102+
ACCOUNT_INDEX=2 DEBUG=false STAKE=100000 CONSOLE_LOG=true ENABLE_DEV_CLIENT_SET_API=true ENABLE_GAS_FEE_WORKAROUND=true node client/index.js
103103
```
104104
You can override default port numbering system by setting `PORT` and `P2P_PORT` environment variables.
105105
Before starting node jobs, remove existing blockchain files and logs if necessary:
@@ -109,10 +109,10 @@ rm -rf /path/to/data/dir logs
109109
The default blockchain data directory is ~/ain_blockchain_data (e.g. chain data will be at ~/ain_blockchain_data/chains). You can use a different directory by specifying the `BLOCKCHAIN_DATA_DIR` environment variable.
110110

111111
The default minimum size of the validator whitelist is 3. Change MIN_NUM_VALIDATORS parameter in
112-
the genesis-configs/base/genesis.json to change this value. You may also need to modify the GENESIS_WHITELIST and GENESIS_VALIDATORS accordingly.
113-
The genesis configs directory used is `genesis-configs/base` by default and it can be altered using `GENESIS_CONFIGS_DIR` env variable. For example, afan shard cluster can use the following command line:
112+
the blockchain-configs/base/genesis.json to change this value. You may also need to modify the GENESIS_WHITELIST and GENESIS_VALIDATORS accordingly.
113+
The genesis configs directory used is `blockchain-configs/base` by default and it can be altered using `BLOCKCHAIN_CONFIGS_DIR` env variable. For example, afan shard cluster can use the following command line:
114114
```
115-
GENESIS_CONFIGS_DIR=genesis-configs/afan-shard MIN_NUM_VALIDATORS=1 ACCOUNT_INDEX=0 DEBUG=false STAKE=100000 CONSOLE_LOG=true ENABLE_DEV_SET_CLIENT_API=true ENABLE_GAS_FEE_WORKAROUND=true node client/index.js
115+
BLOCKCHAIN_CONFIGS_DIR=blockchain-configs/afan-shard MIN_NUM_VALIDATORS=1 ACCOUNT_INDEX=0 DEBUG=false STAKE=100000 CONSOLE_LOG=true ENABLE_DEV_CLIENT_SET_API=true ENABLE_GAS_FEE_WORKAROUND=true node client/index.js
116116
```
117117

118118
#### On Google Cloud Platform (GCP)
Lines changed: 66 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
1+
const logger = new (require('../logger'))('BLOCK_POOL');
2+
13
const _get = require('lodash/get');
2-
const logger = require('../logger')('BLOCK_POOL');
3-
const { ConsensusConsts, ValidatorOffenseTypes } = require('./constants');
4+
const { ConsensusConsts, ValidatorOffenseTypes } = require('../consensus/constants');
45
const { StateVersions } = require('../common/constants');
56
const CommonUtil = require('../common/common-util');
6-
const ConsensusUtil = require('./consensus-util');
7+
const ConsensusUtil = require('../consensus/consensus-util');
78
const Transaction = require('../tx-pool/transaction');
89

910
class BlockPool {
10-
constructor(node, lastBlock) {
11+
constructor(node) {
1112
this.node = node;
1213
const lastFinalizedBlock = this.node.bc.lastBlock();
14+
this.longestNotarizedChainTips = lastFinalizedBlock ? [lastFinalizedBlock.hash] : [];
1315

1416
// Mapping of a block hash to the block's info (block, proposal tx, voting txs)
1517
// e.g. { [<blockHash>]: { block, proposal, votes: { [<address>]: <number> }, tallied } }
@@ -28,41 +30,24 @@ class BlockPool {
2830
// Mapping of a number to a set of block hashes proposed for the number.
2931
// e.g. { [<blockNumber>]: Set<blockHash> }
3032
this.numberToBlockSet = {};
33+
this.heighestSeenBlockNumber = -1;
34+
}
3135

32-
this.longestNotarizedChainTips = [lastFinalizedBlock.hash];
33-
34-
let lastFinalizedBlockHash; let lastFinalizedBlockEpoch; let lastFinalizedBlockNumber;
35-
if (lastFinalizedBlock) {
36-
lastFinalizedBlockHash = lastFinalizedBlock.hash;
37-
lastFinalizedBlockEpoch = lastFinalizedBlock.epoch;
38-
lastFinalizedBlockNumber = lastFinalizedBlock.number;
39-
}
40-
if (lastBlock) {
41-
const lastBlockHash = lastBlock.hash;
42-
const lastBlockEpoch = lastBlock.epoch;
43-
const lastBlockNumber = lastBlock.number;
44-
if (lastFinalizedBlock && lastFinalizedBlock.hash === lastBlock.last_hash) {
45-
const proposal = ConsensusUtil.filterProposalFromVotes(lastBlock.last_votes);
46-
this.hashToBlockInfo[lastFinalizedBlockHash] = {
47-
block: lastFinalizedBlock,
48-
proposal,
49-
votes: lastBlock.last_votes.filter((val) => val.hash !== proposal.hash),
50-
notarized: true
51-
};
52-
this.hashToNextBlockSet[lastFinalizedBlockHash] = new Set([lastBlockHash]);
53-
this.epochToBlock[lastFinalizedBlockEpoch] = lastFinalizedBlockHash;
54-
this.numberToBlockSet[lastFinalizedBlockNumber] = new Set([lastFinalizedBlockHash]);
55-
}
56-
this.hashToBlockInfo[lastBlockHash] = {block: lastBlock};
57-
this.epochToBlock[lastBlockEpoch] = lastBlockHash;
58-
this.numberToBlockSet[lastBlockNumber] = new Set([lastBlockHash]);
59-
} else if (lastFinalizedBlock) {
60-
this.hashToBlockInfo[lastFinalizedBlockHash] = {block: lastFinalizedBlock, notarized: true};
61-
this.epochToBlock[lastFinalizedBlockEpoch] = lastFinalizedBlockHash;
62-
this.numberToBlockSet[lastFinalizedBlockNumber] = new Set([lastFinalizedBlockHash]);
36+
getLongestNotarizedChainHeight() {
37+
return this.longestNotarizedChainTips.length > 0 ?
38+
this.hashToBlockInfo[this.longestNotarizedChainTips[0]].block.number : this.node.bc.lastBlockNumber();
39+
}
40+
41+
updateHighestSeenBlockNumber(blockNumber) {
42+
if (blockNumber > this.heighestSeenBlockNumber) {
43+
this.heighestSeenBlockNumber = blockNumber;
6344
}
6445
}
6546

47+
getHeighestSeenBlockNumber() {
48+
return this.heighestSeenBlockNumber;
49+
}
50+
6651
updateLongestNotarizedChains() {
6752
const LOG_HEADER = 'updateLongestNotarizedChains';
6853
const currentLongest = this.longestNotarizedChainTips.length ?
@@ -120,7 +105,7 @@ class BlockPool {
120105
const LOG_HEADER = 'getLongestNotarizedChainList';
121106
const lastBlockNumber = this.node.bc.lastBlockNumber();
122107
const lastFinalized = fromBlock ? fromBlock
123-
: lastBlockNumber < 1 ? {block: this.node.bc.lastBlock(), notarized: true}
108+
: lastBlockNumber < 1 ? { block: this.node.bc.lastBlock(), notarized: true }
124109
: this.hashToBlockInfo[this.node.bc.lastBlock().hash];
125110
logger.debug(`[${LOG_HEADER}] lastFinalized: ${JSON.stringify(lastFinalized, null, 2)}`);
126111
const chainList = [];
@@ -129,6 +114,7 @@ class BlockPool {
129114
}
130115

131116
dfsLongest(currentNode, currentChain, chainList, withInfo = false) {
117+
const LOG_HEADER = 'dfsLongest';
132118
if (!currentNode || !currentNode.notarized || !currentNode.block) {
133119
return;
134120
}
@@ -143,13 +129,13 @@ class BlockPool {
143129
chainList[0][chainList[0].length - 1].block.number :
144130
chainList[0][chainList[0].length - 1].number : 0;
145131
if (blockNumber > longestNumber) {
146-
logger.debug('[blockPool:dfsLongest] New longest chain found: ' +
132+
logger.debug(`[${LOG_HEADER}] New longest chain found: ` +
147133
`${JSON.stringify(currentChain, null, 2)}, longestNumber: ${blockNumber}`);
148134
chainList.length = 0;
149135
chainList.push([...currentChain]);
150136
longestNumber = blockNumber;
151137
} else if (blockNumber === longestNumber) {
152-
logger.debug('[blockPool:dfsLongest] Another longest chain found: ' +
138+
logger.debug(`[${LOG_HEADER}] Another longest chain found: ` +
153139
`${JSON.stringify(currentChain, null, 2)}, longestNumber: ${blockNumber}`);
154140
chainList.push([...currentChain]);
155141
}
@@ -162,16 +148,26 @@ class BlockPool {
162148
this.dfsLongest(this.hashToBlockInfo[val], currentChain, chainList, withInfo);
163149
}
164150
currentChain.pop();
165-
logger.debug('[blockPool:dfsLongest] returning.. currentChain: ' +
166-
`${JSON.stringify(currentChain, null, 2)}`);
151+
logger.debug(`[${LOG_HEADER}] returning.. currentChain: ${JSON.stringify(currentChain, null, 2)}`);
167152
}
168153

169154
// A finalizable chain (extension of current finalized chain):
170155
// 1. all of its blocks are notarized
171156
// 2. ends with three blocks that have consecutive epoch numbers
172-
getFinalizableChain() {
157+
getFinalizableChain(isGenesisStart) {
158+
const genesisBlockHash = this.node.bc.genesisBlockHash;
159+
const genesisBlockInfo = this.hashToBlockInfo[genesisBlockHash];
160+
const chainWithGenesisBlock = genesisBlockInfo ? [genesisBlockInfo.block] : [];
161+
if (isGenesisStart) {
162+
return chainWithGenesisBlock;
163+
}
173164
const lastFinalized = { block: this.node.bc.lastBlock(), notarized: true };
174-
return this.dfsFinalizable(lastFinalized, []);
165+
const chain = this.dfsFinalizable(lastFinalized, []);
166+
if (chain.length === 0 && this.node.bc.lastBlockNumber() < 0 && this.hashToBlockInfo[genesisBlockHash]) {
167+
// When node first started (fetching from peers or loading from disk)
168+
return chainWithGenesisBlock;
169+
}
170+
return chain;
175171
}
176172

177173
dfsFinalizable(currentNode, currentChain) {
@@ -194,7 +190,7 @@ class BlockPool {
194190
return [...currentChain];
195191
}
196192
let res;
197-
let longest = [];
193+
let longest = BlockPool.endsWithThreeConsecutiveEpochs(currentChain) ? [...currentChain] : [];
198194
for (const blockHash of nextBlockSet) {
199195
res = this.dfsFinalizable(this.hashToBlockInfo[blockHash], currentChain);
200196
if (res && BlockPool.endsWithThreeConsecutiveEpochs(res) && res.length > longest.length) {
@@ -230,10 +226,10 @@ class BlockPool {
230226
hasSeenBlock(blockHash) {
231227
if (this.hashToBlockInfo[blockHash]) {
232228
const blockInfo = this.hashToBlockInfo[blockHash];
233-
return blockInfo && blockInfo.block && (blockInfo.block.number === 0 || !!blockInfo.proposal);
229+
return blockInfo && blockInfo.block;
234230
} else if (this.hashToInvalidBlockInfo[blockHash]) {
235231
const blockInfo = this.hashToInvalidBlockInfo[blockHash];
236-
return blockInfo && blockInfo.block && (blockInfo.block.number === 0 || !!blockInfo.proposal);
232+
return blockInfo && blockInfo.block;
237233
}
238234
return false;
239235
}
@@ -316,10 +312,14 @@ class BlockPool {
316312
this.hashToNextBlockSet[lastHash].add(block.hash);
317313
}
318314

315+
addToHashToDbMap(blockHash, db) {
316+
this.hashToDb.set(blockHash, db);
317+
}
318+
319319
addSeenBlock(block, proposalTx, isValid = true) {
320320
const LOG_HEADER = 'addSeenBlock';
321321
logger.info(
322-
`[${LOG_HEADER}] Adding seen block to the block pool: ${block.number} / ${block.epoch} / ${isValid}`);
322+
`[${LOG_HEADER}] Adding seen block to the block pool: ${block.hash} / ${block.number} / ${block.epoch} / ${isValid}`);
323323
const blockHash = block.hash;
324324
if (isValid) {
325325
if (!this.checkEpochToBlockMap(block)) {
@@ -340,6 +340,7 @@ class BlockPool {
340340
this.addToInvalidBlockInfoMap(block, proposalTx);
341341
this.addToNumberToBlockSet(block);
342342
}
343+
this.updateHighestSeenBlockNumber(block.number);
343344
return true;
344345
}
345346

@@ -417,13 +418,13 @@ class BlockPool {
417418

418419
addProposal(proposalTx, blockHash) {
419420
const LOG_HEADER = 'addProposal';
420-
if (!this.hashToInvalidBlockInfo[blockHash]) {
421-
this.hashToInvalidBlockInfo[blockHash] = {};
422-
} else if (this.hashToInvalidBlockInfo[blockHash].proposal) {
421+
if (!this.hashToBlockInfo[blockHash]) {
422+
this.hashToBlockInfo[blockHash] = {};
423+
} else if (this.hashToBlockInfo[blockHash].proposal) {
423424
logger.debug(`[${LOG_HEADER}] Already have seen this proposal`);
424425
return;
425426
}
426-
this.hashToInvalidBlockInfo[blockHash].proposal = proposalTx;
427+
this.hashToBlockInfo[blockHash].proposal = proposalTx;
427428
logger.debug(`[${LOG_HEADER}] Proposal tx for block added: ${blockHash}`);
428429
}
429430

@@ -434,13 +435,18 @@ class BlockPool {
434435
logger.info(`[${LOG_HEADER}] Current block is unavailable`);
435436
return;
436437
}
438+
if (currentBlockInfo.block.number === 0) {
439+
this.hashToBlockInfo[currentBlockInfo.block.hash].notarized = true;
440+
this.updateLongestNotarizedChains(this.hashToBlockInfo[currentBlockInfo.block.hash]);
441+
return;
442+
}
437443
const lastBlockNumber = currentBlockInfo.block.number - 1;
438444
const lastHash = currentBlockInfo.block.last_hash;
439445
const lastFinalizedBlock = this.node.bc.lastBlock();
440446
let prevBlock;
441-
if (lastBlockNumber === lastFinalizedBlock.number) {
447+
if (lastFinalizedBlock && lastFinalizedBlock.number === lastBlockNumber) {
442448
prevBlock = lastFinalizedBlock;
443-
} else if (lastBlockNumber > lastFinalizedBlock.number) {
449+
} else if (_get(this.hashToBlockInfo[lastHash], 'block')) {
444450
prevBlock = _get(this.hashToBlockInfo[lastHash], 'block');
445451
} else {
446452
prevBlock = this.node.bc.getBlockByHash(lastHash);
@@ -472,12 +478,13 @@ class BlockPool {
472478
}
473479
}
474480

475-
// Remove everything that came before lastBlock including lastBlock.
481+
// Remove everything that came before lastBlock.
476482
cleanUpAfterFinalization(lastBlock, recordedInvalidBlocks) {
477483
const targetNumber = lastBlock.number;
478-
Object.keys(this.numberToBlockSet).forEach((blockNumber) => {
484+
for (const blockNumber of Object.keys(this.numberToBlockSet)) {
479485
if (blockNumber < targetNumber) {
480-
this.numberToBlockSet[blockNumber].forEach((blockHash) => {
486+
const blockHashList = this.numberToBlockSet[blockNumber];
487+
for (const blockHash of blockHashList) {
481488
if (this.hashToInvalidBlockInfo[blockHash]) {
482489
if (recordedInvalidBlocks.has(blockHash) ||
483490
blockNumber < targetNumber - ConsensusConsts.MAX_CONSENSUS_LOGS_IN_STATES) {
@@ -488,19 +495,19 @@ class BlockPool {
488495
this.cleanUpForBlockHash(blockHash);
489496
this.numberToBlockSet[blockNumber].delete(blockHash);
490497
}
491-
});
498+
}
492499
if (!this.numberToBlockSet[blockNumber].size) {
493500
delete this.numberToBlockSet[blockNumber];
494501
}
495502
}
496-
});
497-
Object.keys(this.epochToBlock).forEach((epoch) => {
503+
}
504+
for (const epoch of Object.keys(this.epochToBlock)) {
498505
if (epoch < lastBlock.epoch) {
499506
const blockHash = this.epochToBlock[epoch];
500507
this.cleanUpForBlockHash(blockHash);
501508
delete this.epochToBlock[epoch];
502509
}
503-
});
510+
}
504511
this.updateLongestNotarizedChains();
505512
}
506513

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
{
2+
"token": {
3+
"name": "Fancoin",
4+
"symbol": "FANCO",
5+
"total_supply": 100000000000,
6+
"bridge": {
7+
"AIN": {
8+
"0": {
9+
"0": {
10+
"network_id": 1,
11+
"token_pool": "0xBBB2219cD5eACc54Ce95deF7a67dDe71C8241891",
12+
"min_checkout_per_request": 10000,
13+
"max_checkout_per_request": 100000,
14+
"max_checkout_per_day": 1000000,
15+
"checkout_fee_rate": 0.001,
16+
"token_exchange_rate": 10,
17+
"token_exchange_scheme": "FIXED"
18+
}
19+
}
20+
}
21+
}
22+
},
23+
"blockchain": {
24+
"TRANSACTION_POOL_TIMEOUT_MS": 3600000,
25+
"TRANSACTION_TRACKER_TIMEOUT_MS": 86400000,
26+
"NETWORK_ID": 0,
27+
"CHAIN_ID": 0,
28+
"HOSTING_ENV": "local",
29+
"TRACKER_UPDATE_JSON_RPC_URL": "http://localhost:8080/json-rpc",
30+
"PEER_CANDIDATE_JSON_RPC_URL": "http://localhost:9001/json-rpc",
31+
"MAX_SHARD_REPORT": 100,
32+
"REST_FUNCTION_CALL_TIMEOUT_MS": 10000
33+
},
34+
"genesis": {
35+
"GENESIS_ADDR": "0xBBB2219cD5eACc54Ce95deF7a67dDe71C8241891",
36+
"GENESIS_TIMESTAMP": 1571819318272,
37+
"NUM_GENESIS_ACCOUNTS": 10
38+
},
39+
"consensus": {
40+
"MIN_STAKE_PER_VALIDATOR": 10000000,
41+
"MAX_STAKE_PER_VALIDATOR": 10000000,
42+
"MIN_NUM_VALIDATORS": 3,
43+
"MAX_NUM_VALIDATORS": 9,
44+
"EPOCH_MS": 3000,
45+
"GENESIS_WHITELIST": {
46+
"0x00Ba0Cb2B1157882963024E0CF837E773d11535d": true,
47+
"0x01B6B108bE3FEE00d3661777053175421D806Ea6": true,
48+
"0x02B3a185C6a9DCd643255329d3eB8603E3D0d743": true
49+
},
50+
"GENESIS_VALIDATORS": {
51+
"0x00Ba0Cb2B1157882963024E0CF837E773d11535d": {
52+
"stake": 10000000,
53+
"proposal_right": true
54+
},
55+
"0x01B6B108bE3FEE00d3661777053175421D806Ea6": {
56+
"stake": 10000000,
57+
"proposal_right": true
58+
},
59+
"0x02B3a185C6a9DCd643255329d3eB8603E3D0d743": {
60+
"stake": 10000000,
61+
"proposal_right": true
62+
}
63+
}
64+
},
65+
"network": {
66+
"P2P_MESSAGE_TIMEOUT_MS": 600000,
67+
"TARGET_NUM_OUTBOUND_CONNECTION": 2,
68+
"MAX_NUM_INBOUND_CONNECTION": 3
69+
},
70+
"resource": {
71+
"STATE_TREE_HEIGHT_LIMIT": 30,
72+
"STATE_TREE_BYTES_LIMIT": 5000000000,
73+
"STATE_LABEL_LENGTH_LIMIT": 150,
74+
"TX_BYTES_LIMIT": 10000,
75+
"BATCH_TX_LIST_SIZE_LIMIT": 50,
76+
"TX_POOL_SIZE_LIMIT": 1000,
77+
"TX_POOL_SIZE_LIMIT_PER_ACCOUNT": 100,
78+
"BANDWIDTH_BUDGET_PER_BLOCK": 10000,
79+
"MIN_STAKING_FOR_APP_TX": 0,
80+
"MIN_BALANCE_FOR_SERVICE_TX": 0,
81+
"MAX_FUNCTION_URLS_PER_DEVELOPER": 3
82+
},
83+
"sharding": {
84+
"shard_owner": "0xBBB2219cD5eACc54Ce95deF7a67dDe71C8241891",
85+
"shard_reporter": "0x00Ba0Cb2B1157882963024E0CF837E773d11535d",
86+
"sharding_protocol": "POA",
87+
"sharding_path": "/apps/afan",
88+
"parent_chain_poc": "http://127.0.0.1:8081",
89+
"reporting_period": 5
90+
}
91+
}

0 commit comments

Comments
 (0)