Skip to content

Commit

Permalink
Merge pull request #749 from ainblockchain/release/v0.9.3
Browse files Browse the repository at this point in the history
Merge Release/v0.9.3 into master branch
  • Loading branch information
minsulee2 authored Dec 1, 2021
2 parents df6ffd8 + e6f475e commit 6009504
Show file tree
Hide file tree
Showing 181 changed files with 17,476 additions and 7,853 deletions.
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,9 +97,9 @@ yarn install
```
- Run blockchain nodes
```
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
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
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
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
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
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
```
You can override default port numbering system by setting `PORT` and `P2P_PORT` environment variables.
Before starting node jobs, remove existing blockchain files and logs if necessary:
Expand All @@ -109,10 +109,10 @@ rm -rf /path/to/data/dir logs
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.

The default minimum size of the validator whitelist is 3. Change MIN_NUM_VALIDATORS parameter in
the genesis-configs/base/genesis.json to change this value. You may also need to modify the GENESIS_WHITELIST and GENESIS_VALIDATORS accordingly.
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:
the blockchain-configs/base/genesis.json to change this value. You may also need to modify the GENESIS_WHITELIST and GENESIS_VALIDATORS accordingly.
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:
```
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
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
```

#### On Google Cloud Platform (GCP)
Expand Down
125 changes: 66 additions & 59 deletions consensus/block-pool.js → block-pool/index.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
const logger = new (require('../logger'))('BLOCK_POOL');

const _get = require('lodash/get');
const logger = require('../logger')('BLOCK_POOL');
const { ConsensusConsts, ValidatorOffenseTypes } = require('./constants');
const { ConsensusConsts, ValidatorOffenseTypes } = require('../consensus/constants');
const { StateVersions } = require('../common/constants');
const CommonUtil = require('../common/common-util');
const ConsensusUtil = require('./consensus-util');
const ConsensusUtil = require('../consensus/consensus-util');
const Transaction = require('../tx-pool/transaction');

class BlockPool {
constructor(node, lastBlock) {
constructor(node) {
this.node = node;
const lastFinalizedBlock = this.node.bc.lastBlock();
this.longestNotarizedChainTips = lastFinalizedBlock ? [lastFinalizedBlock.hash] : [];

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

this.longestNotarizedChainTips = [lastFinalizedBlock.hash];

let lastFinalizedBlockHash; let lastFinalizedBlockEpoch; let lastFinalizedBlockNumber;
if (lastFinalizedBlock) {
lastFinalizedBlockHash = lastFinalizedBlock.hash;
lastFinalizedBlockEpoch = lastFinalizedBlock.epoch;
lastFinalizedBlockNumber = lastFinalizedBlock.number;
}
if (lastBlock) {
const lastBlockHash = lastBlock.hash;
const lastBlockEpoch = lastBlock.epoch;
const lastBlockNumber = lastBlock.number;
if (lastFinalizedBlock && lastFinalizedBlock.hash === lastBlock.last_hash) {
const proposal = ConsensusUtil.filterProposalFromVotes(lastBlock.last_votes);
this.hashToBlockInfo[lastFinalizedBlockHash] = {
block: lastFinalizedBlock,
proposal,
votes: lastBlock.last_votes.filter((val) => val.hash !== proposal.hash),
notarized: true
};
this.hashToNextBlockSet[lastFinalizedBlockHash] = new Set([lastBlockHash]);
this.epochToBlock[lastFinalizedBlockEpoch] = lastFinalizedBlockHash;
this.numberToBlockSet[lastFinalizedBlockNumber] = new Set([lastFinalizedBlockHash]);
}
this.hashToBlockInfo[lastBlockHash] = {block: lastBlock};
this.epochToBlock[lastBlockEpoch] = lastBlockHash;
this.numberToBlockSet[lastBlockNumber] = new Set([lastBlockHash]);
} else if (lastFinalizedBlock) {
this.hashToBlockInfo[lastFinalizedBlockHash] = {block: lastFinalizedBlock, notarized: true};
this.epochToBlock[lastFinalizedBlockEpoch] = lastFinalizedBlockHash;
this.numberToBlockSet[lastFinalizedBlockNumber] = new Set([lastFinalizedBlockHash]);
getLongestNotarizedChainHeight() {
return this.longestNotarizedChainTips.length > 0 ?
this.hashToBlockInfo[this.longestNotarizedChainTips[0]].block.number : this.node.bc.lastBlockNumber();
}

updateHighestSeenBlockNumber(blockNumber) {
if (blockNumber > this.heighestSeenBlockNumber) {
this.heighestSeenBlockNumber = blockNumber;
}
}

getHeighestSeenBlockNumber() {
return this.heighestSeenBlockNumber;
}

updateLongestNotarizedChains() {
const LOG_HEADER = 'updateLongestNotarizedChains';
const currentLongest = this.longestNotarizedChainTips.length ?
Expand Down Expand Up @@ -120,7 +105,7 @@ class BlockPool {
const LOG_HEADER = 'getLongestNotarizedChainList';
const lastBlockNumber = this.node.bc.lastBlockNumber();
const lastFinalized = fromBlock ? fromBlock
: lastBlockNumber < 1 ? {block: this.node.bc.lastBlock(), notarized: true}
: lastBlockNumber < 1 ? { block: this.node.bc.lastBlock(), notarized: true }
: this.hashToBlockInfo[this.node.bc.lastBlock().hash];
logger.debug(`[${LOG_HEADER}] lastFinalized: ${JSON.stringify(lastFinalized, null, 2)}`);
const chainList = [];
Expand All @@ -129,6 +114,7 @@ class BlockPool {
}

dfsLongest(currentNode, currentChain, chainList, withInfo = false) {
const LOG_HEADER = 'dfsLongest';
if (!currentNode || !currentNode.notarized || !currentNode.block) {
return;
}
Expand All @@ -143,13 +129,13 @@ class BlockPool {
chainList[0][chainList[0].length - 1].block.number :
chainList[0][chainList[0].length - 1].number : 0;
if (blockNumber > longestNumber) {
logger.debug('[blockPool:dfsLongest] New longest chain found: ' +
logger.debug(`[${LOG_HEADER}] New longest chain found: ` +
`${JSON.stringify(currentChain, null, 2)}, longestNumber: ${blockNumber}`);
chainList.length = 0;
chainList.push([...currentChain]);
longestNumber = blockNumber;
} else if (blockNumber === longestNumber) {
logger.debug('[blockPool:dfsLongest] Another longest chain found: ' +
logger.debug(`[${LOG_HEADER}] Another longest chain found: ` +
`${JSON.stringify(currentChain, null, 2)}, longestNumber: ${blockNumber}`);
chainList.push([...currentChain]);
}
Expand All @@ -162,16 +148,26 @@ class BlockPool {
this.dfsLongest(this.hashToBlockInfo[val], currentChain, chainList, withInfo);
}
currentChain.pop();
logger.debug('[blockPool:dfsLongest] returning.. currentChain: ' +
`${JSON.stringify(currentChain, null, 2)}`);
logger.debug(`[${LOG_HEADER}] returning.. currentChain: ${JSON.stringify(currentChain, null, 2)}`);
}

// A finalizable chain (extension of current finalized chain):
// 1. all of its blocks are notarized
// 2. ends with three blocks that have consecutive epoch numbers
getFinalizableChain() {
getFinalizableChain(isGenesisStart) {
const genesisBlockHash = this.node.bc.genesisBlockHash;
const genesisBlockInfo = this.hashToBlockInfo[genesisBlockHash];
const chainWithGenesisBlock = genesisBlockInfo ? [genesisBlockInfo.block] : [];
if (isGenesisStart) {
return chainWithGenesisBlock;
}
const lastFinalized = { block: this.node.bc.lastBlock(), notarized: true };
return this.dfsFinalizable(lastFinalized, []);
const chain = this.dfsFinalizable(lastFinalized, []);
if (chain.length === 0 && this.node.bc.lastBlockNumber() < 0 && this.hashToBlockInfo[genesisBlockHash]) {
// When node first started (fetching from peers or loading from disk)
return chainWithGenesisBlock;
}
return chain;
}

dfsFinalizable(currentNode, currentChain) {
Expand All @@ -194,7 +190,7 @@ class BlockPool {
return [...currentChain];
}
let res;
let longest = [];
let longest = BlockPool.endsWithThreeConsecutiveEpochs(currentChain) ? [...currentChain] : [];
for (const blockHash of nextBlockSet) {
res = this.dfsFinalizable(this.hashToBlockInfo[blockHash], currentChain);
if (res && BlockPool.endsWithThreeConsecutiveEpochs(res) && res.length > longest.length) {
Expand Down Expand Up @@ -230,10 +226,10 @@ class BlockPool {
hasSeenBlock(blockHash) {
if (this.hashToBlockInfo[blockHash]) {
const blockInfo = this.hashToBlockInfo[blockHash];
return blockInfo && blockInfo.block && (blockInfo.block.number === 0 || !!blockInfo.proposal);
return blockInfo && blockInfo.block;
} else if (this.hashToInvalidBlockInfo[blockHash]) {
const blockInfo = this.hashToInvalidBlockInfo[blockHash];
return blockInfo && blockInfo.block && (blockInfo.block.number === 0 || !!blockInfo.proposal);
return blockInfo && blockInfo.block;
}
return false;
}
Expand Down Expand Up @@ -316,10 +312,14 @@ class BlockPool {
this.hashToNextBlockSet[lastHash].add(block.hash);
}

addToHashToDbMap(blockHash, db) {
this.hashToDb.set(blockHash, db);
}

addSeenBlock(block, proposalTx, isValid = true) {
const LOG_HEADER = 'addSeenBlock';
logger.info(
`[${LOG_HEADER}] Adding seen block to the block pool: ${block.number} / ${block.epoch} / ${isValid}`);
`[${LOG_HEADER}] Adding seen block to the block pool: ${block.hash} / ${block.number} / ${block.epoch} / ${isValid}`);
const blockHash = block.hash;
if (isValid) {
if (!this.checkEpochToBlockMap(block)) {
Expand All @@ -340,6 +340,7 @@ class BlockPool {
this.addToInvalidBlockInfoMap(block, proposalTx);
this.addToNumberToBlockSet(block);
}
this.updateHighestSeenBlockNumber(block.number);
return true;
}

Expand Down Expand Up @@ -417,13 +418,13 @@ class BlockPool {

addProposal(proposalTx, blockHash) {
const LOG_HEADER = 'addProposal';
if (!this.hashToInvalidBlockInfo[blockHash]) {
this.hashToInvalidBlockInfo[blockHash] = {};
} else if (this.hashToInvalidBlockInfo[blockHash].proposal) {
if (!this.hashToBlockInfo[blockHash]) {
this.hashToBlockInfo[blockHash] = {};
} else if (this.hashToBlockInfo[blockHash].proposal) {
logger.debug(`[${LOG_HEADER}] Already have seen this proposal`);
return;
}
this.hashToInvalidBlockInfo[blockHash].proposal = proposalTx;
this.hashToBlockInfo[blockHash].proposal = proposalTx;
logger.debug(`[${LOG_HEADER}] Proposal tx for block added: ${blockHash}`);
}

Expand All @@ -434,13 +435,18 @@ class BlockPool {
logger.info(`[${LOG_HEADER}] Current block is unavailable`);
return;
}
if (currentBlockInfo.block.number === 0) {
this.hashToBlockInfo[currentBlockInfo.block.hash].notarized = true;
this.updateLongestNotarizedChains(this.hashToBlockInfo[currentBlockInfo.block.hash]);
return;
}
const lastBlockNumber = currentBlockInfo.block.number - 1;
const lastHash = currentBlockInfo.block.last_hash;
const lastFinalizedBlock = this.node.bc.lastBlock();
let prevBlock;
if (lastBlockNumber === lastFinalizedBlock.number) {
if (lastFinalizedBlock && lastFinalizedBlock.number === lastBlockNumber) {
prevBlock = lastFinalizedBlock;
} else if (lastBlockNumber > lastFinalizedBlock.number) {
} else if (_get(this.hashToBlockInfo[lastHash], 'block')) {
prevBlock = _get(this.hashToBlockInfo[lastHash], 'block');
} else {
prevBlock = this.node.bc.getBlockByHash(lastHash);
Expand Down Expand Up @@ -472,12 +478,13 @@ class BlockPool {
}
}

// Remove everything that came before lastBlock including lastBlock.
// Remove everything that came before lastBlock.
cleanUpAfterFinalization(lastBlock, recordedInvalidBlocks) {
const targetNumber = lastBlock.number;
Object.keys(this.numberToBlockSet).forEach((blockNumber) => {
for (const blockNumber of Object.keys(this.numberToBlockSet)) {
if (blockNumber < targetNumber) {
this.numberToBlockSet[blockNumber].forEach((blockHash) => {
const blockHashList = this.numberToBlockSet[blockNumber];
for (const blockHash of blockHashList) {
if (this.hashToInvalidBlockInfo[blockHash]) {
if (recordedInvalidBlocks.has(blockHash) ||
blockNumber < targetNumber - ConsensusConsts.MAX_CONSENSUS_LOGS_IN_STATES) {
Expand All @@ -488,19 +495,19 @@ class BlockPool {
this.cleanUpForBlockHash(blockHash);
this.numberToBlockSet[blockNumber].delete(blockHash);
}
});
}
if (!this.numberToBlockSet[blockNumber].size) {
delete this.numberToBlockSet[blockNumber];
}
}
});
Object.keys(this.epochToBlock).forEach((epoch) => {
}
for (const epoch of Object.keys(this.epochToBlock)) {
if (epoch < lastBlock.epoch) {
const blockHash = this.epochToBlock[epoch];
this.cleanUpForBlockHash(blockHash);
delete this.epochToBlock[epoch];
}
});
}
this.updateLongestNotarizedChains();
}

Expand Down
91 changes: 91 additions & 0 deletions blockchain-configs/afan-shard/blockchain_params.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
{
"token": {
"name": "Fancoin",
"symbol": "FANCO",
"total_supply": 100000000000,
"bridge": {
"AIN": {
"0": {
"0": {
"network_id": 1,
"token_pool": "0xBBB2219cD5eACc54Ce95deF7a67dDe71C8241891",
"min_checkout_per_request": 10000,
"max_checkout_per_request": 100000,
"max_checkout_per_day": 1000000,
"checkout_fee_rate": 0.001,
"token_exchange_rate": 10,
"token_exchange_scheme": "FIXED"
}
}
}
}
},
"blockchain": {
"TRANSACTION_POOL_TIMEOUT_MS": 3600000,
"TRANSACTION_TRACKER_TIMEOUT_MS": 86400000,
"NETWORK_ID": 0,
"CHAIN_ID": 0,
"HOSTING_ENV": "local",
"TRACKER_UPDATE_JSON_RPC_URL": "http://localhost:8080/json-rpc",
"PEER_CANDIDATE_JSON_RPC_URL": "http://localhost:9001/json-rpc",
"MAX_SHARD_REPORT": 100,
"REST_FUNCTION_CALL_TIMEOUT_MS": 10000
},
"genesis": {
"GENESIS_ADDR": "0xBBB2219cD5eACc54Ce95deF7a67dDe71C8241891",
"GENESIS_TIMESTAMP": 1571819318272,
"NUM_GENESIS_ACCOUNTS": 10
},
"consensus": {
"MIN_STAKE_PER_VALIDATOR": 10000000,
"MAX_STAKE_PER_VALIDATOR": 10000000,
"MIN_NUM_VALIDATORS": 3,
"MAX_NUM_VALIDATORS": 9,
"EPOCH_MS": 3000,
"GENESIS_WHITELIST": {
"0x00Ba0Cb2B1157882963024E0CF837E773d11535d": true,
"0x01B6B108bE3FEE00d3661777053175421D806Ea6": true,
"0x02B3a185C6a9DCd643255329d3eB8603E3D0d743": true
},
"GENESIS_VALIDATORS": {
"0x00Ba0Cb2B1157882963024E0CF837E773d11535d": {
"stake": 10000000,
"proposal_right": true
},
"0x01B6B108bE3FEE00d3661777053175421D806Ea6": {
"stake": 10000000,
"proposal_right": true
},
"0x02B3a185C6a9DCd643255329d3eB8603E3D0d743": {
"stake": 10000000,
"proposal_right": true
}
}
},
"network": {
"P2P_MESSAGE_TIMEOUT_MS": 600000,
"TARGET_NUM_OUTBOUND_CONNECTION": 2,
"MAX_NUM_INBOUND_CONNECTION": 3
},
"resource": {
"STATE_TREE_HEIGHT_LIMIT": 30,
"STATE_TREE_BYTES_LIMIT": 5000000000,
"STATE_LABEL_LENGTH_LIMIT": 150,
"TX_BYTES_LIMIT": 10000,
"BATCH_TX_LIST_SIZE_LIMIT": 50,
"TX_POOL_SIZE_LIMIT": 1000,
"TX_POOL_SIZE_LIMIT_PER_ACCOUNT": 100,
"BANDWIDTH_BUDGET_PER_BLOCK": 10000,
"MIN_STAKING_FOR_APP_TX": 0,
"MIN_BALANCE_FOR_SERVICE_TX": 0,
"MAX_FUNCTION_URLS_PER_DEVELOPER": 3
},
"sharding": {
"shard_owner": "0xBBB2219cD5eACc54Ce95deF7a67dDe71C8241891",
"shard_reporter": "0x00Ba0Cb2B1157882963024E0CF837E773d11535d",
"sharding_protocol": "POA",
"sharding_path": "/apps/afan",
"parent_chain_poc": "http://127.0.0.1:8081",
"reporting_period": 5
}
}
Loading

0 comments on commit 6009504

Please sign in to comment.