Skip to content

Commit

Permalink
Merge pull request #1170 from ainblockchain/release/v1.0.14
Browse files Browse the repository at this point in the history
Release/v1.0.14
  • Loading branch information
platfowner authored May 12, 2023
2 parents 9ca9812 + ed5668f commit 4acaf02
Show file tree
Hide file tree
Showing 61 changed files with 1,992 additions and 429 deletions.
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM node:16.14
FROM node:18.16
WORKDIR /app/ain-blockchain
COPY . /app/ain-blockchain
RUN yarn install
Expand Down
9 changes: 8 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,13 @@ You can use some environment variables, and these have the following options.
-e ACCOUNT_INJECTION_OPTION={private_key|keystore|mnemonic}
-e SYNC_MODE={fast|full|peer}
-e STAKE=<YOUR_TARGET_STAKE>
-e HOSTING_ENV={local|comcom|gcp|aws}
```
You can mount a volume when you meet some wants.
1. Want to preserve blockchain data in the docker container when changing the docker image due to an update.
2. Want to save your keystore file in the docker container when injecting your account into the blockchain automatically.
```
-v <YOUR_VOLUME>:/home/ain_blockchain_data
```
After the node is executed, you should inject your account into the node.
```
Expand All @@ -180,7 +187,7 @@ node inject_node_account.js <NODE_ENDPOINT_URL> --mnemonic
If you want to inject your account automatically, add one of these environment variables before running the node.
```
-e ACCOUNT_INJECTION_OPTION=private_key -e PRIVATE_KEY=<YOUR_PRIVATE_KEY>
-e ACCOUNT_INJECTION_OPTION=keystore -e KEYSTORE_FILE_PATH="/path/to/keystore" -e PASSWORD=<YOUR_PASSWORD>
-e ACCOUNT_INJECTION_OPTION=keystore -e KEYSTORE_FILE_PATH="/home/ain_blockchain_data/<KEYSTORE>" -e PASSWORD=<YOUR_PASSWORD>
-e ACCOUNT_INJECTION_OPTION=mnemonic -e MNEMONIC="your mnemonic"
```

Expand Down
3 changes: 3 additions & 0 deletions client/protocol_versions.json
Original file line number Diff line number Diff line change
Expand Up @@ -116,5 +116,8 @@
},
"1.0.13": {
"min": "1.0.0"
},
"1.0.14": {
"min": "1.0.0"
}
}
4 changes: 4 additions & 0 deletions common/common-util.js
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,10 @@ class CommonUtil {
return ruleUtil.isValidatorOffenseType(type);
}

static isValidUrlWhitelistItem(url) {
return ruleUtil.isValidUrlWhitelistItem(url);
}

static isValidUrl(url) {
return ruleUtil.isValidUrl(url);
}
Expand Down
13 changes: 13 additions & 0 deletions common/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,18 @@ function setNodeConfigs() {
setNodeConfigs();

// ** Enums **
/**
* Hosting Environments.
*
* @enum {string}
*/
const HostingEnvs = {
AWS: 'aws', // Amazon AWS
COMCOM: 'comcom', // ComCom On-Premise
LOCAL: 'local', // Local
GCP: 'gcp', // Google Cloud Platform
};

/**
* Types of P2P network messages.
*
Expand Down Expand Up @@ -821,6 +833,7 @@ module.exports = {
TimerFlagEnabledBandageMap,
BlockchainParams,
NodeConfigs,
HostingEnvs,
P2pMessageTypes,
BlockchainNodeStates,
P2pNetworkStates,
Expand Down
35 changes: 29 additions & 6 deletions common/network-util.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,17 @@ const logger = new (require('../logger'))('NETWORK-UTIL');

const _ = require('lodash');
const axios = require('axios');
const { BlockchainConsts, NodeConfigs } = require('../common/constants');
const { BlockchainConsts, NodeConfigs, HostingEnvs } = require('../common/constants');
const ip = require('ip');
const extIp = require('ext-ip')();
const CommonUtil = require('../common/common-util');
const DB = require('../db');
const { JSON_RPC_METHODS } = require('../json_rpc/constants');
const GCP_EXTERNAL_IP_URL = 'http://metadata.google.internal/computeMetadata/v1/instance' +
'/network-interfaces/0/access-configs/0/external-ip';
const GCP_INTERNAL_IP_URL = 'http://metadata.google.internal/computeMetadata/v1/instance' +
'/network-interfaces/0/ip';
const GCP_EXTERNAL_IP_URL = 'http://metadata.google.internal/computeMetadata/v1/instance/network-interfaces/0/access-configs/0/external-ip';
const GCP_INTERNAL_IP_URL = 'http://metadata.google.internal/computeMetadata/v1/instance/network-interfaces/0/ip';
const AWS_TOKEN_URL = 'http://169.254.169.254/latest/api/token';
const AWS_EXTERNAL_IP_URL = 'http://169.254.169.254/latest/meta-data/public-ipv4';
const AWS_INTERNAL_IP_URL = 'http://169.254.169.254/latest/meta-data/local-ipv4';

axios.defaults.timeout = NodeConfigs.DEFAULT_AXIOS_REQUEST_TIMEOUT;

Expand Down Expand Up @@ -96,7 +97,7 @@ function sendGetRequest(endpoint, method, params) {
function getIpAddress(internal = false) {
return Promise.resolve()
.then(() => {
if (NodeConfigs.HOSTING_ENV === 'gcp') {
if (NodeConfigs.HOSTING_ENV === HostingEnvs.GCP) {
return axios.get(internal ? GCP_INTERNAL_IP_URL : GCP_EXTERNAL_IP_URL, {
headers: {'Metadata-Flavor': 'Google'},
timeout: 3000
Expand All @@ -108,6 +109,28 @@ function getIpAddress(internal = false) {
CommonUtil.finishWithStackTrace(
logger, `Failed to get ip address: ${JSON.stringify(err, null, 2)}`);
});
} else if (NodeConfigs.HOSTING_ENV === HostingEnvs.AWS) {
const token = axios.put(AWS_TOKEN_URL, { }, {
headers: {'X-aws-ec2-metadata-token-ttl-seconds': 21600}
})
.then((res) => {
return res.data;
})
.catch((err) => {
CommonUtil.finishWithStackTrace(
logger, `Failed to get aws token: ${JSON.stringify(err, null, 2)}`);
});
return axios.get(internal ? AWS_INTERNAL_IP_URL : AWS_EXTERNAL_IP_URL, {
headers: {'X-aws-ec2-metadata-token': token},
timeout: 3000
})
.then((res) => {
return res.data;
})
.catch((err) => {
CommonUtil.finishWithStackTrace(
logger, `Failed to get ip address: ${JSON.stringify(err, null, 2)}`);
});
} else {
if (internal) {
return ip.address();
Expand Down
9 changes: 8 additions & 1 deletion config_client_api_ip_whitelist.sh
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,13 @@ printf "Enter password: "
read -s PASSWORD
printf "\n\n"
if [[ $SEASON = "mainnet" ]]; then
CHAIN_ID="1"
KEYSTORE_DIR="mainnet_prod_keys"
elif [[ $SEASON = "spring" ]] || [[ $SEASON = "summer" ]]; then
CHAIN_ID="0"
KEYSTORE_DIR="testnet_prod_keys"
else
CHAIN_ID="0"
KEYSTORE_DIR="testnet_dev_staging_keys"
fi

Expand All @@ -87,14 +90,18 @@ else
COMMAND_NODE_JS_FILE="getDevClientApiIpWhitelist.js"
fi

printf "CHAIN_ID=$CHAIN_ID\n"
printf "KEYSTORE_DIR=$KEYSTORE_DIR\n"
printf "COMMAND_NODE_JS_FILE=$COMMAND_NODE_JS_FILE\n"

function config_node() {
local node_index="$1"
local node_ip_addr=${IP_ADDR_LIST[${node_index}]}

printf "\n\n<<< Configuring ip whitelist of node $node_index ($node_ip_addr) >>>\n\n"

KEYSTORE_FILE_PATH="$KEYSTORE_DIR/keystore_node_$node_index.json"
CONFIG_NODE_CMD="node tools/api-access/$COMMAND_NODE_JS_FILE $node_ip_addr 0 keystore $KEYSTORE_FILE_PATH"
CONFIG_NODE_CMD="node tools/api-access/$COMMAND_NODE_JS_FILE $node_ip_addr $CHAIN_ID keystore $KEYSTORE_FILE_PATH"
if [[ ! $COMMAND = "get" ]]; then
CONFIG_NODE_CMD="$CONFIG_NODE_CMD '$IP_ADDR'"
fi
Expand Down
10 changes: 9 additions & 1 deletion config_node_param.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ function usage() {
printf "Example: bash config_node_param.sh dev add DEV_CLIENT_API_IP_WHITELIST '*'\n"
printf "Example: bash config_node_param.sh dev remove DEV_CLIENT_API_IP_WHITELIST 32.190.239.181\n"
printf "Example: bash config_node_param.sh dev set DEV_CLIENT_API_IP_WHITELIST '*'\n"
printf "Example: bash config_node_param.sh dev get CORS_WHITELIST\n"
printf "\n"
exit
}
Expand Down Expand Up @@ -80,10 +81,13 @@ printf "Enter password: "
read -s PASSWORD
printf "\n\n"
if [[ $SEASON = "mainnet" ]]; then
CHAIN_ID="1"
KEYSTORE_DIR="mainnet_prod_keys"
elif [[ $SEASON = "spring" ]] || [[ $SEASON = "summer" ]]; then
CHAIN_ID="0"
KEYSTORE_DIR="testnet_prod_keys"
else
CHAIN_ID="0"
KEYSTORE_DIR="testnet_dev_staging_keys"
fi

Expand All @@ -97,14 +101,18 @@ else
COMMAND_NODE_JS_FILE="getNodeParam.js"
fi

printf "CHAIN_ID=$CHAIN_ID\n"
printf "KEYSTORE_DIR=$KEYSTORE_DIR\n"
printf "COMMAND_NODE_JS_FILE=$COMMAND_NODE_JS_FILE\n"

function config_node() {
local node_index="$1"
local node_ip_addr=${IP_ADDR_LIST[${node_index}]}

printf "\n\n<<< Configuring ip whitelist of node $node_index ($node_ip_addr) >>>\n\n"

KEYSTORE_FILE_PATH="$KEYSTORE_DIR/keystore_node_$node_index.json"
CONFIG_NODE_CMD="node tools/api-access/$COMMAND_NODE_JS_FILE $node_ip_addr 0 keystore $KEYSTORE_FILE_PATH $PARAM"
CONFIG_NODE_CMD="node tools/api-access/$COMMAND_NODE_JS_FILE $node_ip_addr $CHAIN_ID keystore $KEYSTORE_FILE_PATH $PARAM"
if [[ ! $COMMAND = "get" ]]; then
CONFIG_NODE_CMD="$CONFIG_NODE_CMD '$VALUE'"
fi
Expand Down
3 changes: 2 additions & 1 deletion consensus/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const PushId = require('../db/push-id');
const {
BlockchainConsts,
NodeConfigs,
HostingEnvs,
WriteDbOperations,
PredefinedDbPaths,
StateVersions,
Expand Down Expand Up @@ -155,7 +156,7 @@ class Consensus {
this.isInEpochTransition = true;
this.node.tryFinalizeChain();
let currentTime = Date.now();
if (NodeConfigs.HOSTING_ENV !== 'local' &&
if (NodeConfigs.HOSTING_ENV !== HostingEnvs.LOCAL &&
(this.epoch % 10 === 0 || CommonUtil.timestampExceedsThreshold(
this.ntpData.syncedAt, healthThresholdEpoch * epochMs))) {
// adjust time
Expand Down
97 changes: 55 additions & 42 deletions db/functions.js
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ class Functions {
const timestamp = _.get(options, 'timestamp', null);
const blockNumber = _.get(options, 'blockNumber', null);
const blockTime = _.get(options, 'blockTime', null);
const eventSource = _.get(options, 'eventSource', null);
let triggerCount = 0;
let failCount = 0;
const promises = [];
Expand Down Expand Up @@ -190,7 +191,6 @@ class Functions {
const newAuth = Object.assign(
{}, auth, { fid: functionEntry.function_id, fids: this.getFids() });
let result = null;
const eventSource = _.get(options, 'eventSource', null);
try {
result = nativeFunction.func(
value,
Expand All @@ -208,11 +208,11 @@ class Functions {
blockNumber,
blockTime,
options,
eventSource,
auth: newAuth,
opResultList: [],
otherGasAmount: 0,
...blockchainParams,
eventSource,
});
funcResults[functionEntry.function_id] = result;
if (DevFlags.enableRichFunctionLogging) {
Expand All @@ -236,51 +236,64 @@ class Functions {
}
}
} else if (functionEntry.function_type === FunctionTypes.REST) {
if (NodeConfigs.ENABLE_REST_FUNCTION_CALL && functionEntry.function_url &&
CommonUtil.isWhitelistedUrl(functionEntry.function_url, this.db.getRestFunctionsUrlWhitelist())) {
if (DevFlags.enableRichFunctionLogging) {
// NOTE: Skipped when the event source is null.
if (NodeConfigs.ENABLE_REST_FUNCTION_CALL &&
eventSource !== null &&
functionEntry.function_url) {
const restFunctionUrlWhitelist = this.db.getRestFunctionsUrlWhitelist();
if (!CommonUtil.isWhitelistedUrl(functionEntry.function_url, restFunctionUrlWhitelist)) {
// NOTE: Skipped when the function url is not in the whitelist.
logger.info(
` ==> Triggering REST function [[ ${functionEntry.function_id} ]] of ` +
`function_url '${functionEntry.function_url}' with:\n` +
`Skipped triggering REST function [[ ${functionEntry.function_id} ]] of ` +
`function_url '${functionEntry.function_url}' which is NOT in the whitelist: \n` +
`${JSON.stringify(restFunctionUrlWhitelist)}` +
formattedParams);
}
const newAuth = Object.assign(
{}, auth, { fid: functionEntry.function_id, fids: this.getFids() });
promises.push(axios.post(functionEntry.function_url, {
fid: functionEntry.function_id,
function: functionEntry,
valuePath,
functionPath,
value,
prevValue,
params,
timestamp,
executedAt,
transaction,
blockNumber,
blockTime,
options,
auth: newAuth,
chainId: blockchainParams.chainId,
networkId: blockchainParams.networkId,
}, {
timeout: NodeConfigs.REST_FUNCTION_CALL_TIMEOUT_MS
}).catch((error) => {
} else {
if (DevFlags.enableRichFunctionLogging) {
logger.error(
`Failed to trigger REST function [[ ${functionEntry.function_id} ]] of ` +
`function_url '${functionEntry.function_url}' with error: \n` +
`${JSON.stringify(error)}` +
logger.info(
` ==> Triggering REST function [[ ${functionEntry.function_id} ]] of ` +
`function_url '${functionEntry.function_url}' with:\n` +
formattedParams);
}
failCount++;
return true;
}));
funcResults[functionEntry.function_id] = {
code: FunctionResultCode.SUCCESS,
bandwidth_gas_amount: blockchainParams.restFunctionCallGasAmount,
};
triggerCount++;
const newAuth = Object.assign(
{}, auth, { fid: functionEntry.function_id, fids: this.getFids() });
promises.push(axios.post(functionEntry.function_url, {
fid: functionEntry.function_id,
function: functionEntry,
valuePath,
functionPath,
value,
prevValue,
params,
timestamp,
executedAt,
transaction,
blockNumber,
blockTime,
options,
eventSource,
auth: newAuth,
chainId: blockchainParams.chainId,
networkId: blockchainParams.networkId,
}, {
timeout: NodeConfigs.REST_FUNCTION_CALL_TIMEOUT_MS
}).catch((error) => {
if (DevFlags.enableRichFunctionLogging) {
logger.error(
`Failed to trigger REST function [[ ${functionEntry.function_id} ]] of ` +
`function_url '${functionEntry.function_url}' with error: \n` +
`${JSON.stringify(error)}` +
formattedParams);
}
failCount++;
return true;
}));
funcResults[functionEntry.function_id] = {
code: FunctionResultCode.SUCCESS,
bandwidth_gas_amount: blockchainParams.restFunctionCallGasAmount,
};
triggerCount++;
}
}
}
}
Expand Down
3 changes: 2 additions & 1 deletion db/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -1073,7 +1073,8 @@ class DB {
logger.debug(
`[${LOG_HEADER}] applyStateGcRuleRes: deleted ${applyStateGcRuleRes} child nodes`);
}
if (this.eh) {
// NOTE: Skipped when the event source is null.
if (this.eh && eventSource !== null) {
this.eh.emitValueChanged(auth, transaction, localPath, prevValueCopy, valueCopy, eventSource);
}

Expand Down
3 changes: 2 additions & 1 deletion event-handler/event-channel-manager.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const { getIpAddress } = require('../common/network-util');
const {
BlockchainEventMessageTypes,
NodeConfigs,
HostingEnvs,
BlockchainEventTypes,
FilterDeletionReasons,
} = require('../common/constants');
Expand All @@ -23,7 +24,7 @@ class EventChannelManager {
}

async getNetworkInfo() {
const ipAddr = await getIpAddress(NodeConfigs.HOSTING_ENV === 'comcom' || NodeConfigs.HOSTING_ENV === 'local');
const ipAddr = await getIpAddress(NodeConfigs.HOSTING_ENV === HostingEnvs.COMCOM || NodeConfigs.HOSTING_ENV === HostingEnvs.LOCAL);
const eventHandlerUrl = new URL(`ws://${ipAddr}:${NodeConfigs.EVENT_HANDLER_PORT}`);
return {
url: eventHandlerUrl.toString(),
Expand Down
Loading

0 comments on commit 4acaf02

Please sign in to comment.