diff --git a/e2e/Makefile b/e2e/Makefile index 33aaf36..d381001 100644 --- a/e2e/Makefile +++ b/e2e/Makefile @@ -2,6 +2,8 @@ chain: make -C chains build make -C chains network + # Wait for one epoch to use BEP-120 validator + sleep 100 .PHONY:contracts contracts: diff --git a/e2e/chains/bsc/Dockerfile.bootstrap b/e2e/chains/bsc/Dockerfile.bootstrap index 20705f3..df89ccd 100644 --- a/e2e/chains/bsc/Dockerfile.bootstrap +++ b/e2e/chains/bsc/Dockerfile.bootstrap @@ -1,11 +1,13 @@ FROM ethereum/solc:0.6.4-alpine -RUN apk add --d --no-cache ca-certificates npm nodejs bash alpine-sdk +RUN apk add --d --no-cache ca-certificates npm nodejs bash alpine-sdk expect jq -RUN git clone https://github.com/binance-chain/bsc-genesis-contract.git /root/genesis -RUN cd /root/genesis && git checkout 461d9a1f0d0bcc5fc2d4cd39c4b748185eaae34c -RUN cd /root/genesis && npm install +RUN git clone https://github.com/binance-chain/bsc-genesis-contract.git -b v1.1.9 /root/genesis \ + && cd /root/genesis && npm ci +COPY scripts/contracts/SystemReward.template /root/genesis/contracts/SystemReward.template +COPY scripts/contracts/BSCValidatorSet.template /root/genesis/contracts/BSCValidatorSet.template +COPY scripts/generate-validator.js /root/genesis/generate-validator.js COPY scripts/genesis-template.template /root/genesis/genesis-template.template COPY scripts/init_holders.template /root/genesis/init_holders.template diff --git a/e2e/chains/bsc/Dockerfile.bsc b/e2e/chains/bsc/Dockerfile.bsc index 0be2dec..02a53e3 100644 --- a/e2e/chains/bsc/Dockerfile.bsc +++ b/e2e/chains/bsc/Dockerfile.bsc @@ -1,10 +1,13 @@ -FROM golang:1.16-alpine +FROM golang:1.19-alpine ARG GIT_SOURCE ARG GIT_CHECKOUT_BRANCH -RUN apk add --no-cache make gcc musl-dev linux-headers git +RUN apk add --no-cache make cmake gcc musl-dev linux-headers git bash build-base libc-dev +ENV CGO_CFLAGS="-O -D__BLST_PORTABLE__" +ENV CGO_CFLAGS_ALLOW="-O -D__BLST_PORTABLE__" +RUN echo v15 RUN cd / && git clone --depth 1 -b ${GIT_CHECKOUT_BRANCH} ${GIT_SOURCE} \ && cd ./bsc && make geth diff --git a/e2e/chains/bsc/Makefile b/e2e/chains/bsc/Makefile index 33b624d..38c837d 100644 --- a/e2e/chains/bsc/Makefile +++ b/e2e/chains/bsc/Makefile @@ -10,8 +10,8 @@ bootstrap: .PHONY:network network: - docker compose -f docker-compose.simple.yml up -d bsc-rpc bsc-validator1-1 bsc-validator1-2 bsc-validator1-3 bsc-validator1-4 bsc-validator1-5 - docker compose -f docker-compose.simple.yml up -d bsc-rpc2 bsc-validator2-1 bsc-validator2-2 bsc-validator2-3 bsc-validator2-4 bsc-validator2-5 + docker compose -f docker-compose.simple.yml up -d bsc-rpc bsc-validator1-1 bsc-validator1-2 bsc-validator1-3 + docker compose -f docker-compose.simple.yml up -d bsc-rpc2 bsc-validator2-1 bsc-validator2-2 bsc-validator2-3 .PHONY:network-down network-down: diff --git a/e2e/chains/bsc/config/config-validator.toml b/e2e/chains/bsc/config/config-validator.toml index 53ed911..f526831 100644 --- a/e2e/chains/bsc/config/config-validator.toml +++ b/e2e/chains/bsc/config/config-validator.toml @@ -37,6 +37,8 @@ Percentile = 60 OracleThreshold = 100 [Node] +BLSPasswordFile="/root/.ethereum/blspassword.txt" +BLSWalletDir="/root/.ethereum/bls/wallet" DataDir = "" InsecureUnlockAllowed = false NoUSB = true diff --git a/e2e/chains/bsc/docker-compose.bsc.yml b/e2e/chains/bsc/docker-compose.bsc.yml index 68a5f0e..a536d57 100644 --- a/e2e/chains/bsc/docker-compose.bsc.yml +++ b/e2e/chains/bsc/docker-compose.bsc.yml @@ -7,5 +7,5 @@ services: dockerfile: Dockerfile.bsc args: GIT_SOURCE: https://github.com/binance-chain/bsc.git - GIT_CHECKOUT_BRANCH: v1.1.17 + GIT_CHECKOUT_BRANCH: v1.2.10 image: bsc-geth:docker-local diff --git a/e2e/chains/bsc/docker-compose.simple.yml b/e2e/chains/bsc/docker-compose.simple.yml index 65d8f54..02b37bd 100644 --- a/e2e/chains/bsc/docker-compose.simple.yml +++ b/e2e/chains/bsc/docker-compose.simple.yml @@ -23,7 +23,7 @@ services: environment: BLOCKS_PER_EPOCH: 20 INIT_HOLDER_BALANCE: "500000000000000000000" - NUMS_OF_VALIDATOR: 5 + NUMS_OF_VALIDATOR: 3 volumes: - bsc-rpc:/root/storage/bsc-rpc - bsc-validator1-1:/root/storage/bsc-validator1 @@ -34,7 +34,8 @@ services: - ./scripts:/root/scripts - ./config:/root/config - ./init-holders:/root/init-holders - # - ./validators/keystore:/root/validators/keystore + - ./validators/bls:/root/validators/bls + - ./validators/keystore:/root/validators/keystore command: /root/scripts/bootstrap.sh bootstrap-simple2: @@ -45,7 +46,7 @@ services: environment: BLOCKS_PER_EPOCH: 20 INIT_HOLDER_BALANCE: "500000000000000000000" - NUMS_OF_VALIDATOR: 5 + NUMS_OF_VALIDATOR: 3 volumes: - bsc-rpc2:/root/storage/bsc-rpc - bsc-validator2-1:/root/storage/bsc-validator1 @@ -56,7 +57,8 @@ services: - ./scripts:/root/scripts - ./config:/root/config - ./init-holders:/root/init-holders - # - ./validators/keystore:/root/validators/keystore + - ./validators/bls:/root/validators/bls + - ./validators/keystore:/root/validators/keystore command: /root/scripts/bootstrap.sh bsc-rpc: # This is the bootstrap node diff --git a/e2e/chains/bsc/scripts/bootstrap.sh b/e2e/chains/bsc/scripts/bootstrap.sh index 8e784ce..565c726 100755 --- a/e2e/chains/bsc/scripts/bootstrap.sh +++ b/e2e/chains/bsc/scripts/bootstrap.sh @@ -1,5 +1,4 @@ #!/usr/bin/env bash -set -eu workspace=$( cd $(dirname $0) @@ -18,13 +17,20 @@ function prepare() { function init_validator() { node_id=$1 - geth --datadir ${workspace}/storage/${node_id} account new --password /dev/null >${workspace}/storage/${node_id}Info - validatorAddr=$(cat ${workspace}/storage/${node_id}Info | grep 'Public address of the key' | awk '{print $6}') - #mkdir -p ${workspace}/storage/${node_id}/keystore - #cp ${workspace}/validators/keystore/${node_id} ${workspace}/storage/${node_id}/keystore/${node_id} - #validatorAddr="0xa7876ea32e7a748c697d01345145485561305b24" - echo "${validatorAddr},${validatorAddr},${validatorAddr},0x0000000010000000" >>${workspace}/genesis/validators.conf + + # set validator address + mkdir -p ${workspace}/storage/${node_id}/keystore + cp ${workspace}/validators/keystore/${node_id} ${workspace}/storage/${node_id}/keystore/${node_id} + validatorAddr=0x$(cat ${workspace}/storage/${node_id}/keystore/${node_id} | jq .address | sed 's/"//g') echo ${validatorAddr} >${workspace}/storage/${node_id}/address + + # import BLS vote address + echo password01 > ${workspace}/storage/${node_id}/blspassword.txt + geth --datadir ${workspace}/storage/${node_id} bls account import ${workspace}/validators/bls/${node_id} --blspassword ${workspace}/storage/${node_id}/blspassword.txt --blsaccountpassword ${workspace}/storage/${node_id}/blspassword.txt + geth --datadir ${workspace}/storage/${node_id} bls account list --blspassword ${workspace}/storage/${node_id}/blspassword.txt + voteAddr=0x$(cat ${workspace}/validators/bls/${node_id} | jq .pubkey | sed 's/"//g') + + echo "${validatorAddr},${validatorAddr},${validatorAddr},0x0000000010000000,${voteAddr}" >>${workspace}/genesis/validators.conf } function generate_genesis() { @@ -36,7 +42,6 @@ function generate_genesis() { node generate-validator.js chainIDHex=$(printf '%04x\n' ${BSC_CHAIN_ID}) node generate-genesis.js --chainid ${BSC_CHAIN_ID} --bscChainId ${chainIDHex} - #cat ${workspace}/genesis/genesis.json } function init_genesis_data() { @@ -57,6 +62,7 @@ prepare # First, generate config for each validator for ((i = 1; i <= ${NUMS_OF_VALIDATOR}; i++)); do init_validator "bsc-validator${i}" + generate_validator_conf "bsc-validator${i}" done # Then, use validator configs to generate genesis file diff --git a/e2e/chains/bsc/scripts/bsc-validator.sh b/e2e/chains/bsc/scripts/bsc-validator.sh index 0f855c8..6a9d0a5 100755 --- a/e2e/chains/bsc/scripts/bsc-validator.sh +++ b/e2e/chains/bsc/scripts/bsc-validator.sh @@ -16,4 +16,4 @@ geth --config ${DATA_DIR}/config.toml --datadir ${DATA_DIR} --netrestrict ${CLUS --mine -unlock ${VALIDATOR_ADDR} --password /dev/null \ --light.serve 50 --pprof.addr 0.0.0.0 --metrics \ --rpc.allow-unprotected-txs --txlookuplimit 15768000 \ - --pprof --ipcpath /gethipc + --pprof --ipcpath /gethipc --vote diff --git a/e2e/chains/bsc/scripts/contracts/BSCValidatorSet.template b/e2e/chains/bsc/scripts/contracts/BSCValidatorSet.template new file mode 100644 index 0000000..144070a --- /dev/null +++ b/e2e/chains/bsc/scripts/contracts/BSCValidatorSet.template @@ -0,0 +1,1078 @@ +pragma solidity 0.6.4; +pragma experimental ABIEncoderV2; + +import "./System.sol"; +import "./lib/BytesLib.sol"; +import "./lib/BytesToTypes.sol"; +import "./lib/Memory.sol"; +import "./interface/ILightClient.sol"; +import "./interface/ISlashIndicator.sol"; +import "./interface/ITokenHub.sol"; +import "./interface/IRelayerHub.sol"; +import "./interface/IParamSubscriber.sol"; +import "./interface/IBSCValidatorSet.sol"; +import "./interface/IApplication.sol"; +import "./lib/SafeMath.sol"; +import "./lib/RLPDecode.sol"; +import "./lib/CmnPkg.sol"; + + +contract BSCValidatorSet is IBSCValidatorSet, System, IParamSubscriber, IApplication { + + using SafeMath for uint256; + + using RLPDecode for *; + + // will not transfer value less than 0.1 BNB for validators + uint256 constant public DUSTY_INCOMING = 1e17; + + uint8 public constant JAIL_MESSAGE_TYPE = 1; + uint8 public constant VALIDATORS_UPDATE_MESSAGE_TYPE = 0; + + // the precision of cross chain value transfer. + uint256 public constant PRECISION = 1e10; + uint256 public constant EXPIRE_TIME_SECOND_GAP = 1000; + uint256 public constant MAX_NUM_OF_VALIDATORS = 41; + + bytes public constant INIT_VALIDATORSET_BYTES = hex"{{initValidatorSetBytes}}"; + + uint32 public constant ERROR_UNKNOWN_PACKAGE_TYPE = 101; + uint32 public constant ERROR_FAIL_CHECK_VALIDATORS = 102; + uint32 public constant ERROR_LEN_OF_VAL_MISMATCH = 103; + uint32 public constant ERROR_RELAYFEE_TOO_LARGE = 104; + + uint256 public constant INIT_NUM_OF_CABINETS = 21; + uint256 public constant EPOCH = 200; + + /*********************** state of the contract **************************/ + Validator[] public currentValidatorSet; + uint256 public expireTimeSecondGap; + uint256 public totalInComing; + + // key is the `consensusAddress` of `Validator`, + // value is the index of the element in `currentValidatorSet`. + mapping(address =>uint256) public currentValidatorSetMap; + uint256 public numOfJailed; + + uint256 public constant BURN_RATIO_SCALE = 10000; + address public constant BURN_ADDRESS = 0x000000000000000000000000000000000000dEaD; + uint256 public constant INIT_BURN_RATIO = {{initBurnRatio}}; + uint256 public burnRatio; + bool public burnRatioInitialized; + + // BEP-127 Temporary Maintenance + uint256 public constant INIT_MAX_NUM_OF_MAINTAINING = 3; + uint256 public constant INIT_MAINTAIN_SLASH_SCALE = 2; + + uint256 public maxNumOfMaintaining; + uint256 public numOfMaintaining; + uint256 public maintainSlashScale; + + // Corresponds strictly to currentValidatorSet + // validatorExtraSet[index] = the `ValidatorExtra` info of currentValidatorSet[index] + ValidatorExtra[] public validatorExtraSet; + // BEP-131 candidate validator + uint256 public numOfCabinets; + uint256 public maxNumOfCandidates; + uint256 public maxNumOfWorkingCandidates; + + // BEP-126 Fast Finality + uint256 public constant INIT_FINALITY_REWARD_RATIO = 50; + uint256 public constant MAX_SYSTEM_REWARD_BALANCE = 100 ether; + + uint256 public finalityRewardRatio; + uint256 public previousHeight; + uint256 public previousBalanceOfSystemReward; + + struct Validator { + address consensusAddress; + address payable feeAddress; + address BBCFeeAddress; + uint64 votingPower; + + // only in state + bool jailed; + uint256 incoming; + } + + struct ValidatorExtra { + // BEP-127 Temporary Maintenance + uint256 enterMaintenanceHeight; // the height from where the validator enters Maintenance + bool isMaintaining; + + // BEP-126 Fast Finality + bytes voteAddress; + + // reserve for future use + uint256[19] slots; + } + + /*********************** cross chain package **************************/ + struct IbcValidatorSetPackage { + uint8 packageType; + Validator[] validatorSet; + bytes[] voteAddrs; + } + + /*********************** modifiers **************************/ + modifier noEmptyDeposit() { + require(msg.value > 0, "deposit value is zero"); + _; + } + + modifier initValidatorExtraSet() { + if (validatorExtraSet.length == 0) { + ValidatorExtra memory validatorExtra; + // init validatorExtraSet + uint256 validatorsNum = currentValidatorSet.length; + for (uint i; i previousHeight, "can not do this twice in one block"); + _; + previousHeight = block.number; + } + + /*********************** events **************************/ + event validatorSetUpdated(); + event validatorJailed(address indexed validator); + event validatorEmptyJailed(address indexed validator); + event batchTransfer(uint256 amount); + event batchTransferFailed(uint256 indexed amount, string reason); + event batchTransferLowerFailed(uint256 indexed amount, bytes reason); + event systemTransfer(uint256 amount); + event directTransfer(address payable indexed validator, uint256 amount); + event directTransferFail(address payable indexed validator, uint256 amount); + event deprecatedDeposit(address indexed validator, uint256 amount); + event validatorDeposit(address indexed validator, uint256 amount); + event validatorMisdemeanor(address indexed validator, uint256 amount); + event validatorFelony(address indexed validator, uint256 amount); + event failReasonWithStr(string message); + event unexpectedPackage(uint8 channelId, bytes msgBytes); + event paramChange(string key, bytes value); + event feeBurned(uint256 amount); + event validatorEnterMaintenance(address indexed validator); + event validatorExitMaintenance(address indexed validator); + event finalityRewardDeposit(address indexed validator, uint256 amount); + event deprecatedFinalityRewardDeposit(address indexed validator, uint256 amount); + + /*********************** init **************************/ + function init() external onlyNotInit{ + (IbcValidatorSetPackage memory validatorSetPkg, bool valid)= decodeValidatorSetSynPackage(INIT_VALIDATORSET_BYTES); + require(valid, "failed to parse init validatorSet"); + for (uint i; i 0 && curBurnRatio > 0) { + uint256 toBurn = value.mul(curBurnRatio).div(BURN_RATIO_SCALE); + if (toBurn > 0) { + address(uint160(BURN_ADDRESS)).transfer(toBurn); + emit feeBurned(toBurn); + + value = value.sub(toBurn); + } + } + + if (index>0) { + Validator storage validator = currentValidatorSet[index-1]; + if (validator.jailed) { + emit deprecatedDeposit(valAddr,value); + } else { + totalInComing = totalInComing.add(value); + validator.incoming = validator.incoming.add(value); + emit validatorDeposit(valAddr,value); + } + } else { + // get incoming from deprecated validator; + emit deprecatedDeposit(valAddr,value); + } + } + + function jailValidator(Validator memory v) internal returns (uint32) { + uint256 index = currentValidatorSetMap[v.consensusAddress]; + if (index==0 || currentValidatorSet[index-1].jailed) { + emit validatorEmptyJailed(v.consensusAddress); + return CODE_OK; + } + uint n = currentValidatorSet.length; + bool shouldKeep = (numOfJailed >= n-1); + // will not jail if it is the last valid validator + if (shouldKeep) { + emit validatorEmptyJailed(v.consensusAddress); + return CODE_OK; + } + ++numOfJailed; + currentValidatorSet[index-1].jailed = true; + emit validatorJailed(v.consensusAddress); + return CODE_OK; + } + + function updateValidatorSet(Validator[] memory validatorSet, bytes[] memory voteAddrs) internal returns (uint32) { + { + // do verify. + if (validatorSet.length > MAX_NUM_OF_VALIDATORS) { + emit failReasonWithStr("the number of validators exceed the limit"); + return ERROR_FAIL_CHECK_VALIDATORS; + } + for (uint i; i= DUSTY_INCOMING) { + ++crossSize; + } else if (currentValidatorSet[i].incoming > 0) { + ++directSize; + } + } + + //cross transfer + address[] memory crossAddrs = new address[](crossSize); + uint256[] memory crossAmounts = new uint256[](crossSize); + uint256[] memory crossIndexes = new uint256[](crossSize); + address[] memory crossRefundAddrs = new address[](crossSize); + uint256 crossTotal; + // direct transfer + address payable[] memory directAddrs = new address payable[](directSize); + uint256[] memory directAmounts = new uint256[](directSize); + crossSize = 0; + directSize = 0; + uint256 relayFee = ITokenHub(TOKEN_HUB_ADDR).getMiniRelayFee(); + if (relayFee > DUSTY_INCOMING) { + emit failReasonWithStr("fee is larger than DUSTY_INCOMING"); + return ERROR_RELAYFEE_TOO_LARGE; + } + for (uint i; i= DUSTY_INCOMING) { + crossAddrs[crossSize] = currentValidatorSet[i].BBCFeeAddress; + uint256 value = currentValidatorSet[i].incoming - currentValidatorSet[i].incoming % PRECISION; + crossAmounts[crossSize] = value.sub(relayFee); + crossRefundAddrs[crossSize] = currentValidatorSet[i].feeAddress; + crossIndexes[crossSize] = i; + crossTotal = crossTotal.add(value); + ++crossSize; + } else if (currentValidatorSet[i].incoming > 0) { + directAddrs[directSize] = currentValidatorSet[i].feeAddress; + directAmounts[directSize] = currentValidatorSet[i].incoming; + ++directSize; + } + } + + //step 2: do cross chain transfer + bool failCross = false; + if (crossTotal > 0) { + try ITokenHub(TOKEN_HUB_ADDR).batchTransferOutBNB{value : crossTotal}(crossAddrs, crossAmounts, crossRefundAddrs, uint64(block.timestamp + expireTimeSecondGap)) returns (bool success) { + if (success) { + emit batchTransfer(crossTotal); + } else { + emit batchTransferFailed(crossTotal, "batch transfer return false"); + } + }catch Error(string memory reason) { + failCross = true; + emit batchTransferFailed(crossTotal, reason); + }catch (bytes memory lowLevelData) { + failCross = true; + emit batchTransferLowerFailed(crossTotal, lowLevelData); + } + } + + if (failCross) { + for (uint i; i0) { + for (uint i; i0) { + emit systemTransfer(address(this).balance); + address(uint160(SYSTEM_REWARD_ADDR)).transfer(address(this).balance); + } + // step 5: do update validator set state + totalInComing = 0; + numOfJailed = 0; + if (validatorSetTemp.length>0) { + doUpdateState(validatorSetTemp, voteAddrsTemp); + } + + // step 6: clean slash contract + ISlashIndicator(SLASH_CONTRACT_ADDR).clean(); + emit validatorSetUpdated(); + return CODE_OK; + } + + /** + * @dev With each epoch, there will be a partial rotation between cabinets and candidates. Rotation is determined by this function + * + */ + function shuffle(address[] memory validators, bytes[] memory voteAddrs, uint256 epochNumber, uint startIdx, uint offset, uint limit, uint modNumber) internal pure { + for (uint i; i 0) { + uint256 epochNumber = block.number / EPOCH; + shuffle(validators, voteAddrs, epochNumber, _numOfCabinets-_maxNumOfWorkingCandidates, 0, _maxNumOfWorkingCandidates, _numOfCabinets); + shuffle(validators, voteAddrs, epochNumber, _numOfCabinets-_maxNumOfWorkingCandidates, _numOfCabinets-_maxNumOfWorkingCandidates, + _maxNumOfWorkingCandidates, validators.length - _numOfCabinets+_maxNumOfWorkingCandidates); + } + address[] memory miningValidators = new address[](_numOfCabinets); + bytes[] memory miningVoteAddrs = new bytes[](_numOfCabinets); + for (uint i; i<_numOfCabinets; ++i) { + miningValidators[i] = validators[i]; + miningVoteAddrs[i] = voteAddrs[i]; + } + return (miningValidators, miningVoteAddrs); + } + + /** + * @dev Get all validators, including all of the cabinets and all of the candidates + * + */ + function getValidators() public view returns(address[] memory) { + uint n = currentValidatorSet.length; + uint valid = 0; + for (uint i; i= currentValidatorSet.length) { + return false; + } + + // validatorExtraSet[index] should not be used before it has been init. + if (index >= validatorExtraSet.length) { + return !currentValidatorSet[index].jailed; + } + + return !currentValidatorSet[index].jailed && !validatorExtraSet[index].isMaintaining; + } + + function getIncoming(address validator)external view returns(uint256) { + uint256 index = currentValidatorSetMap[validator]; + if (index<=0) { + return 0; + } + return currentValidatorSet[index-1].incoming; + } + + function isCurrentValidator(address validator) external view override returns (bool) { + uint256 index = currentValidatorSetMap[validator]; + if (index <= 0) { + return false; + } + + // the actual index + index = index - 1; + return isWorkingValidator(index); + } + + function distributeFinalityReward(address[] calldata valAddrs, uint256[] calldata weights) external onlyCoinbase oncePerBlock onlyInit { + // first time to call this function + if (finalityRewardRatio == 0) { + finalityRewardRatio = INIT_FINALITY_REWARD_RATIO; + previousBalanceOfSystemReward = address(SYSTEM_REWARD_ADDR).balance; + return; + } + + uint256 totalValue; + uint256 balanceOfSystemReward = address(SYSTEM_REWARD_ADDR).balance; + if (balanceOfSystemReward > MAX_SYSTEM_REWARD_BALANCE) { + totalValue = balanceOfSystemReward.div(100); + } else if (balanceOfSystemReward > previousBalanceOfSystemReward) { + // when a slash happens, theres will no rewards in some epoches, + // it's tolerated because slash happens rarely + totalValue = (balanceOfSystemReward.sub(previousBalanceOfSystemReward)).mul(finalityRewardRatio).div(100); + } else { + return; + } + + totalValue = ISystemReward(SYSTEM_REWARD_ADDR).claimRewards(payable(address(this)), totalValue); + previousBalanceOfSystemReward = address(SYSTEM_REWARD_ADDR).balance; + if (totalValue == 0) { + return; + } + + uint256 totalWeight; + for (uint256 i; i 0) { + Validator storage validator = currentValidatorSet[index - 1]; + if (validator.jailed) { + emit deprecatedFinalityRewardDeposit(valAddr, value); + } else { + totalInComing = totalInComing.add(value); + validator.incoming = validator.incoming.add(value); + emit finalityRewardDeposit(valAddr, value); + } + } else { + // get incoming from deprecated validator; + emit deprecatedFinalityRewardDeposit(valAddr, value); + } + } + + } + + function getWorkingValidatorCount() public view returns(uint256 workingValidatorCount) { + workingValidatorCount = getValidators().length; + uint256 _numOfCabinets = numOfCabinets > 0 ? numOfCabinets : INIT_NUM_OF_CABINETS; + if (workingValidatorCount > _numOfCabinets) { + workingValidatorCount = _numOfCabinets; + } + if (workingValidatorCount == 0) { + workingValidatorCount = 1; + } + } + /*********************** For slash **************************/ + function misdemeanor(address validator) external onlySlash initValidatorExtraSet override { + uint256 validatorIndex = _misdemeanor(validator); + if (canEnterMaintenance(validatorIndex)) { + _enterMaintenance(validator, validatorIndex); + } + } + + function felony(address validator)external onlySlash initValidatorExtraSet override{ + uint256 index = currentValidatorSetMap[validator]; + if (index <= 0) { + return; + } + // the actual index + index = index - 1; + + bool isMaintaining = validatorExtraSet[index].isMaintaining; + if (_felony(validator, index) && isMaintaining) { + --numOfMaintaining; + } + } + + /*********************** For Temporary Maintenance **************************/ + function getCurrentValidatorIndex(address _validator) public view returns (uint256) { + uint256 index = currentValidatorSetMap[_validator]; + require(index > 0, "only current validators"); + + // the actual index + return index - 1; + } + + function canEnterMaintenance(uint256 index) public view returns (bool) { + if (index >= currentValidatorSet.length) { + return false; + } + + if ( + currentValidatorSet[index].consensusAddress == address(0) // - 0. check if empty validator + || (maxNumOfMaintaining == 0 || maintainSlashScale == 0) // - 1. check if not start + || numOfMaintaining >= maxNumOfMaintaining // - 2. check if reached upper limit + || !isWorkingValidator(index) // - 3. check if not working(not jailed and not maintaining) + || validatorExtraSet[index].enterMaintenanceHeight > 0 // - 5. check if has Maintained during current 24-hour period + // current validators are selected every 24 hours(from 00:00:00 UTC to 23:59:59 UTC) + // for more details, refer to https://github.com/bnb-chain/docs-site/blob/master/docs/smart-chain/validator/Binance%20Smart%20Chain%20Validator%20FAQs%20-%20Updated.md + || getValidators().length <= 1 // - 6. check num of remaining working validators + ) { + return false; + } + + return true; + } + + + /** + * @dev Enter maintenance for current validators. refer to https://github.com/bnb-chain/BEPs/blob/master/BEP127.md + * + */ + function enterMaintenance() external initValidatorExtraSet { + // check maintain config + if (maxNumOfMaintaining == 0) { + maxNumOfMaintaining = INIT_MAX_NUM_OF_MAINTAINING; + } + if (maintainSlashScale == 0) { + maintainSlashScale = INIT_MAINTAIN_SLASH_SCALE; + } + + uint256 index = getCurrentValidatorIndex(msg.sender); + require(canEnterMaintenance(index), "can not enter Temporary Maintenance"); + _enterMaintenance(msg.sender, index); + } + + /** + * @dev Exit maintenance for current validators. refer to https://github.com/bnb-chain/BEPs/blob/master/BEP127.md + * + */ + function exitMaintenance() external { + uint256 index = getCurrentValidatorIndex(msg.sender); + + // jailed validators are allowed to exit maintenance + require(validatorExtraSet[index].isMaintaining, "not in maintenance"); + uint256 workingValidatorCount = getWorkingValidatorCount(); + _exitMaintenance(msg.sender, index, workingValidatorCount); + } + + /*********************** Param update ********************************/ + function updateParam(string calldata key, bytes calldata value) override external onlyInit onlyGov{ + if (Memory.compareStrings(key, "expireTimeSecondGap")) { + require(value.length == 32, "length of expireTimeSecondGap mismatch"); + uint256 newExpireTimeSecondGap = BytesToTypes.bytesToUint256(32, value); + require(newExpireTimeSecondGap >=100 && newExpireTimeSecondGap <= 1e5, "the expireTimeSecondGap is out of range"); + expireTimeSecondGap = newExpireTimeSecondGap; + } else if (Memory.compareStrings(key, "burnRatio")) { + require(value.length == 32, "length of burnRatio mismatch"); + uint256 newBurnRatio = BytesToTypes.bytesToUint256(32, value); + require(newBurnRatio <= BURN_RATIO_SCALE, "the burnRatio must be no greater than 10000"); + burnRatio = newBurnRatio; + burnRatioInitialized = true; + } else if (Memory.compareStrings(key, "maxNumOfMaintaining")) { + require(value.length == 32, "length of maxNumOfMaintaining mismatch"); + uint256 newMaxNumOfMaintaining = BytesToTypes.bytesToUint256(32, value); + uint256 _numOfCabinets = numOfCabinets; + if (_numOfCabinets == 0) { + _numOfCabinets = INIT_NUM_OF_CABINETS; + } + require(newMaxNumOfMaintaining < _numOfCabinets, "the maxNumOfMaintaining must be less than numOfCabinets"); + maxNumOfMaintaining = newMaxNumOfMaintaining; + } else if (Memory.compareStrings(key, "maintainSlashScale")) { + require(value.length == 32, "length of maintainSlashScale mismatch"); + uint256 newMaintainSlashScale = BytesToTypes.bytesToUint256(32, value); + require(newMaintainSlashScale > 0 && newMaintainSlashScale < 10, "the maintainSlashScale must be greater than 0 and less than 10"); + maintainSlashScale = newMaintainSlashScale; + } else if (Memory.compareStrings(key, "maxNumOfWorkingCandidates")) { + require(value.length == 32, "length of maxNumOfWorkingCandidates mismatch"); + uint256 newMaxNumOfWorkingCandidates = BytesToTypes.bytesToUint256(32, value); + require(newMaxNumOfWorkingCandidates <= maxNumOfCandidates, "the maxNumOfWorkingCandidates must be not greater than maxNumOfCandidates"); + maxNumOfWorkingCandidates = newMaxNumOfWorkingCandidates; + } else if (Memory.compareStrings(key, "maxNumOfCandidates")) { + require(value.length == 32, "length of maxNumOfCandidates mismatch"); + uint256 newMaxNumOfCandidates = BytesToTypes.bytesToUint256(32, value); + maxNumOfCandidates = newMaxNumOfCandidates; + if (maxNumOfWorkingCandidates > maxNumOfCandidates) { + maxNumOfWorkingCandidates = maxNumOfCandidates; + } + } else if (Memory.compareStrings(key, "numOfCabinets")) { + require(value.length == 32, "length of numOfCabinets mismatch"); + uint256 newNumOfCabinets = BytesToTypes.bytesToUint256(32, value); + require(newNumOfCabinets > 0, "the numOfCabinets must be greater than 0"); + require(newNumOfCabinets <= MAX_NUM_OF_VALIDATORS, "the numOfCabinets must be less than MAX_NUM_OF_VALIDATORS"); + numOfCabinets = newNumOfCabinets; + } else if (Memory.compareStrings(key, "finalityRewardRatio")) { + require(value.length == 32, "length of finalityRewardRatio mismatch"); + uint256 newFinalityRewardRatio = BytesToTypes.bytesToUint256(32, value); + require(newFinalityRewardRatio >= 1 && newFinalityRewardRatio <= 100, "the finalityRewardRatio is out of range"); + finalityRewardRatio = newFinalityRewardRatio; + } else { + require(false, "unknown param"); + } + emit paramChange(key, value); + } + + /*********************** Internal Functions **************************/ + function doUpdateState(Validator[] memory newValidatorSet, bytes[] memory newVoteAddrs) private { + uint n = currentValidatorSet.length; + uint m = newValidatorSet.length; + + // delete stale validators + for (uint i; im) { + for (uint i=m; in) { + ValidatorExtra memory _validatorExtra; + for (uint i=n; i < m; ++i) { + _validatorExtra.voteAddress = newVoteAddrs[i]; + currentValidatorSet.push(newValidatorSet[i]); + validatorExtraSet.push(_validatorExtra); + currentValidatorSetMap[newValidatorSet[i].consensusAddress] = i+1; + } + } + + // make sure all new validators are cleared maintainInfo + // should not happen, still protect + numOfMaintaining = 0; + n = currentValidatorSet.length; + for (uint i; i 0; --index) { + i = index - 1; // the actual index + if (!validatorExtraSet[i].isMaintaining) { + continue; + } + + // only maintaining validators + validator = currentValidatorSet[i].consensusAddress; + + // exit maintenance + isFelony = _exitMaintenance(validator, i, workingValidatorCount); + if (!isFelony || numOfFelony >= _validatorSet.length - 1) { + continue; + } + + // record the jailed validator in validatorSet + for (uint k; k<_validatorSet.length; ++k) { + if (_validatorSet[k].consensusAddress == validator) { + _validatorSet[k].jailed = true; + ++numOfFelony; + break; + } + } + } + + // 2. get unjailed validators from validatorSet + unjailedValidatorSet = new Validator[](_validatorSet.length - numOfFelony); + unjailedVoteAddrs = new bytes[](_validatorSet.length - numOfFelony); + i = 0; + for (uint index; index<_validatorSet.length; ++index) { + if (!_validatorSet[index].jailed) { + unjailedValidatorSet[i] = _validatorSet[index]; + unjailedVoteAddrs[i] = _voteAddrs[index]; + ++i; + } + } + + return (unjailedValidatorSet, unjailedVoteAddrs); + } + + function _enterMaintenance(address validator, uint256 index) private { + ++numOfMaintaining; + validatorExtraSet[index].isMaintaining = true; + validatorExtraSet[index].enterMaintenanceHeight = block.number; + emit validatorEnterMaintenance(validator); + } + + function _exitMaintenance(address validator, uint index, uint256 workingValidatorCount) private returns (bool isFelony){ + if (maintainSlashScale == 0 || workingValidatorCount == 0 || numOfMaintaining == 0) { + // should not happen, still protect + return false; + } + + // step 0: modify numOfMaintaining + --numOfMaintaining; + + // step 1: calculate slashCount + uint256 slashCount = + block.number + .sub(validatorExtraSet[index].enterMaintenanceHeight) + .div(workingValidatorCount) + .div(maintainSlashScale); + + // step 2: clear maintaining info of the validator + validatorExtraSet[index].isMaintaining = false; + + // step3: slash the validator + (uint256 misdemeanorThreshold, uint256 felonyThreshold) = ISlashIndicator(SLASH_CONTRACT_ADDR).getSlashThresholds(); + isFelony = false; + if (slashCount >= felonyThreshold) { + _felony(validator, index); + ISlashIndicator(SLASH_CONTRACT_ADDR).sendFelonyPackage(validator); + isFelony = true; + } else if (slashCount >= misdemeanorThreshold) { + _misdemeanor(validator); + } + + emit validatorExitMaintenance(validator); + } + + //rlp encode & decode function + function decodeValidatorSetSynPackage(bytes memory msgBytes) internal pure returns(IbcValidatorSetPackage memory, bool) { + IbcValidatorSetPackage memory validatorSetPkg; + + RLPDecode.Iterator memory iter = msgBytes.toRLPItem().iterator(); + bool success = false; + uint256 idx=0; + while (iter.hasNext()) { + if (idx == 0) { + validatorSetPkg.packageType = uint8(iter.next().toUint()); + } else if (idx == 1) { + RLPDecode.RLPItem[] memory items = iter.next().toList(); + validatorSetPkg.validatorSet = new Validator[](items.length); + validatorSetPkg.voteAddrs = new bytes[](items.length); + for (uint j; j bool) operators; + + modifier doInit() { + if (!alreadyInit) { + operators[LIGHT_CLIENT_ADDR] = true; + operators[INCENTIVIZE_ADDR] = true; + numOperator = 2; + alreadyInit = true; + } + _; + } + + modifier onlyOperator() { +// start mod + // require(operators[msg.sender],"only operator is allowed to call the method"); +// end mod + _; + } + + event rewardTo(address indexed to, uint256 amount); + event rewardEmpty(); + event receiveDeposit(address indexed from, uint256 amount); + event addOperator(address indexed operator); + event deleteOperator(address indexed operator); + event paramChange(string key, bytes value); + + receive() external payable{ + if (msg.value>0) { + emit receiveDeposit(msg.sender, msg.value); + } + } + + function claimRewards(address payable to, uint256 amount) external override(ISystemReward) doInit onlyOperator returns (uint256) { + uint256 actualAmount = amount < address(this).balance ? amount : address(this).balance; + if (actualAmount > MAX_REWARDS) { + actualAmount = MAX_REWARDS; + } + if (actualAmount != 0) { + to.transfer(actualAmount); + emit rewardTo(to, actualAmount); + } else { + emit rewardEmpty(); + } + return actualAmount; + } + + function isOperator(address addr) external view returns (bool) { + return operators[addr]; + } + + function updateParam(string calldata key, bytes calldata value) onlyGov external override { + if (Memory.compareStrings(key, "addOperator")) { + bytes memory valueLocal = value; + require(valueLocal.length == 20, "length of value for addOperator should be 20"); + address operatorAddr; + assembly { + operatorAddr := mload(add(valueLocal, 20)) + } + operators[operatorAddr] = true; + emit addOperator(operatorAddr); + } else if (Memory.compareStrings(key, "deleteOperator")) { + bytes memory valueLocal = value; + require(valueLocal.length == 20, "length of value for deleteOperator should be 20"); + address operatorAddr; + assembly { + operatorAddr := mload(add(valueLocal, 20)) + } + delete operators[operatorAddr]; + emit deleteOperator(operatorAddr); + } else { + require(false, "unknown param"); + } + emit paramChange(key, value); + } +} \ No newline at end of file diff --git a/e2e/chains/bsc/scripts/create_bls_key.sh b/e2e/chains/bsc/scripts/create_bls_key.sh new file mode 100644 index 0000000..a1a4d97 --- /dev/null +++ b/e2e/chains/bsc/scripts/create_bls_key.sh @@ -0,0 +1,17 @@ +#!/usr/bin/expect +# 6 num wanted +set wallet_password 123456 +# 10 characters at least wanted +set account_password 1234567890 + +set timeout 5 +spawn geth bls account new --datadir [lindex $argv 0] +expect "*assword:*" +send "$wallet_password\r" +expect "*assword:*" +send "$wallet_password\r" +expect "*assword:*" +send "$account_password\r" +expect "*assword:*" +send "$account_password\r" +expect EOF \ No newline at end of file diff --git a/e2e/chains/bsc/scripts/generate-validator.js b/e2e/chains/bsc/scripts/generate-validator.js new file mode 100644 index 0000000..2c4e174 --- /dev/null +++ b/e2e/chains/bsc/scripts/generate-validator.js @@ -0,0 +1,37 @@ +const fs = require("fs"); +const readline = require('readline'); +const nunjucks = require("nunjucks"); + +async function processValidatorConf() { + const fileStream = fs.createReadStream(__dirname + "/validators.conf"); + + const rl = readline.createInterface({ + input: fileStream, + crlfDelay: Infinity + }); + let validators = []; + for await (const line of rl) { + // Each line in input.txt will be successively available here as `line`. + let vs = line.split(",") + validators.push({ + consensusAddr: vs[0], + feeAddr: vs[1], + bscFeeAddr: vs[2], + votingPower: vs[3], + bLSPublicKey: vs[4] + }); + } + return validators +} + +processValidatorConf().then(function (validators) { + console.log("start generate validator ") + console.log(validators) + const data = { + validators: validators, + }; + const templateString = fs.readFileSync(__dirname + '/validators.template').toString(); + const resultString = nunjucks.renderString(templateString, data); + fs.writeFileSync(__dirname + '/validators.js', resultString); + console.log("BSCValidatorSet file updated."); +}) \ No newline at end of file diff --git a/e2e/chains/bsc/scripts/genesis-template.template b/e2e/chains/bsc/scripts/genesis-template.template index 134baf2..e41461f 100644 --- a/e2e/chains/bsc/scripts/genesis-template.template +++ b/e2e/chains/bsc/scripts/genesis-template.template @@ -26,7 +26,7 @@ "epoch": {{BLOCKS_PER_EPOCH}} } }, - "nonce": "0x0", + "nonce": "0x0", "timestamp": "0x5e9da7ce", "extraData": "{{extraData}}", "gasLimit": "0x2625a00", @@ -94,4 +94,4 @@ "number": "0x0", "gasUsed": "0x0", "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000" -} +} \ No newline at end of file diff --git a/e2e/chains/bsc/validators/bls/bsc-validator1 b/e2e/chains/bsc/validators/bls/bsc-validator1 new file mode 100644 index 0000000..13da523 --- /dev/null +++ b/e2e/chains/bsc/validators/bls/bsc-validator1 @@ -0,0 +1,31 @@ +{ + "crypto": { + "checksum": { + "function": "sha256", + "message": "6793d94172c0582ef0875348d964fc32fd9d278b631030aa096673ff7fbee711", + "params": {} + }, + "cipher": { + "function": "aes-128-ctr", + "message": "2ca733434906ba0069a1bcca74fd1ec451694b235650201b7063f5ba55abb668", + "params": { + "iv": "97ab231c587bbeab26578dc00d385c0f" + } + }, + "kdf": { + "function": "pbkdf2", + "message": "", + "params": { + "c": 262144, + "dklen": 32, + "prf": "hmac-sha256", + "salt": "b4f60e8963fc392141f02a94efc2d5e0c87145d491707afb7301cc7c7bb1c703" + } + } + }, + "uuid": "b124fa34-21f1-4801-a2bc-4d990c27d95e", + "pubkey": "a4f05ea3dd58373394ba3a7ca3cabec78b69e044b2b09e82171d82e6e3998a9ed1f82226cd4540bcc8c3bafa8c9c7251", + "version": 4, + "name": "keystore", + "path": "" +} \ No newline at end of file diff --git a/e2e/chains/bsc/validators/bls/bsc-validator2 b/e2e/chains/bsc/validators/bls/bsc-validator2 new file mode 100644 index 0000000..637c6bd --- /dev/null +++ b/e2e/chains/bsc/validators/bls/bsc-validator2 @@ -0,0 +1,31 @@ +{ + "crypto": { + "checksum": { + "function": "sha256", + "message": "446362983492fb6ae7d6f5e11b14bc794854c81060f9d7a71d6cbe912a4e476f", + "params": {} + }, + "cipher": { + "function": "aes-128-ctr", + "message": "822df2a93774f43c2322a60f785f220decb27637afaaaf62cc81db8c29aebce7", + "params": { + "iv": "31924604b957f4deabb4b1997fc1e199" + } + }, + "kdf": { + "function": "pbkdf2", + "message": "", + "params": { + "c": 262144, + "dklen": 32, + "prf": "hmac-sha256", + "salt": "46d7e1613c5b49d5a296e796f4a4d27664e2e2ebed798437c8fccae37750c207" + } + } + }, + "uuid": "c2f31107-bd81-46ea-bf63-167abce1fd8f", + "pubkey": "ab63700b5d3f58338176990c8488a7c319480310b5ec39d23453839ff26116b29a91e20f834835c5e6f670961d7df8ff", + "version": 4, + "name": "keystore", + "path": "" +} \ No newline at end of file diff --git a/e2e/chains/bsc/validators/bls/bsc-validator3 b/e2e/chains/bsc/validators/bls/bsc-validator3 new file mode 100644 index 0000000..43f27f0 --- /dev/null +++ b/e2e/chains/bsc/validators/bls/bsc-validator3 @@ -0,0 +1,31 @@ +{ + "crypto": { + "checksum": { + "function": "sha256", + "message": "34f2294c70ff2368afe63b5524c69fa5c547531316911113d0be79fc21583e42", + "params": {} + }, + "cipher": { + "function": "aes-128-ctr", + "message": "df0f1b67f001e4aff159edee56bfd1e16d992175924ef25b3f386def39432c5b", + "params": { + "iv": "3d5aa1978a4f1ae9e894299131189d0d" + } + }, + "kdf": { + "function": "pbkdf2", + "message": "", + "params": { + "c": 262144, + "dklen": 32, + "prf": "hmac-sha256", + "salt": "2ad40f34204dde80eec78c0b40189936733c62ac7bfaebc837e3f627199147ce" + } + } + }, + "uuid": "fe7876c3-2f05-4ea4-9a6e-f52d9237a9fe", + "pubkey": "8bb6a87761d9668637faacae15f907dd813ea1df4f85062fa5535765c198bb9d55293684a75d3a12e65215a8b410f207", + "version": 4, + "name": "keystore", + "path": "" +} \ No newline at end of file diff --git a/e2e/chains/bsc/validators/bls/bsc-validator4 b/e2e/chains/bsc/validators/bls/bsc-validator4 new file mode 100644 index 0000000..387e676 --- /dev/null +++ b/e2e/chains/bsc/validators/bls/bsc-validator4 @@ -0,0 +1,31 @@ +{ + "crypto": { + "checksum": { + "function": "sha256", + "message": "e63b5440e98197567b30abcf375b032735563fa6ce24bdb19e7097b686ae2323", + "params": {} + }, + "cipher": { + "function": "aes-128-ctr", + "message": "fc913fcfac8544e758efd1e3d7c69593d4c72d5f2605f5fec463083bca99c986", + "params": { + "iv": "2fd0910320da40f251cb8431e953c9f5" + } + }, + "kdf": { + "function": "pbkdf2", + "message": "", + "params": { + "c": 262144, + "dklen": 32, + "prf": "hmac-sha256", + "salt": "73cfb64e17c67106737a6fbff2be743c2274544106285334efc0a2727c4ee7fe" + } + } + }, + "uuid": "09ccc666-4af7-410e-a244-c7308e125ef9", + "pubkey": "9616539495727baf00e640a5ce5ade7016dc7aea50bfccc6bf03cdcd7a4062c3d4b42a6f262a7b70d9ad3133d2dc18f5", + "version": 4, + "name": "keystore", + "path": "" +} \ No newline at end of file diff --git a/e2e/chains/bsc/validators/bls/bsc-validator5 b/e2e/chains/bsc/validators/bls/bsc-validator5 new file mode 100644 index 0000000..ad61078 --- /dev/null +++ b/e2e/chains/bsc/validators/bls/bsc-validator5 @@ -0,0 +1,31 @@ +{ + "crypto": { + "checksum": { + "function": "sha256", + "message": "5062814a439458a8e7154fcda6d95b73d539a5b1758511ad2743a4450fe6e688", + "params": {} + }, + "cipher": { + "function": "aes-128-ctr", + "message": "a85b7bf484648ac778d3becda35c3e5f5f4395ce263ec668e0c8f35c82c1aff0", + "params": { + "iv": "d630a629b49631bc2c5882510f129905" + } + }, + "kdf": { + "function": "pbkdf2", + "message": "", + "params": { + "c": 262144, + "dklen": 32, + "prf": "hmac-sha256", + "salt": "ed4b2ba87aa91b6a6e2a26d34f15143034551812b477c468f6d2cdf24a44bfdc" + } + } + }, + "uuid": "f2d12d84-ab52-4a54-97b1-6a2eb1b357f9", + "pubkey": "9083c35d129344d2ab141cdc20060f08886526f825344203b449acb7d51bf2ccfd8dac764835323ea540338c8392a642", + "version": 4, + "name": "keystore", + "path": "" +} \ No newline at end of file diff --git a/e2e/chains/bsc/validators/keystore/bsc-validator2 b/e2e/chains/bsc/validators/keystore/bsc-validator2 new file mode 100644 index 0000000..9202b99 --- /dev/null +++ b/e2e/chains/bsc/validators/keystore/bsc-validator2 @@ -0,0 +1 @@ +{"address":"d9a13701eafb76870cb220843b8c6476824bfa15","crypto":{"cipher":"aes-128-ctr","ciphertext":"7e1301dbed559fffbb8fe53c4d46350bedb5ac35a5ff335d51542edffc81185c","cipherparams":{"iv":"a676aedbaa26bcd0a9a06e5af5cf1900"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"03b2f7a24b292ed3d4d4d073873bddbe69538e84f07285780a72cdd58fee523d"},"mac":"f2ad5c3351249cef4b23f3d49aec225d7f0f0b62ed87681f06d41ce2ab6ed48e"},"id":"7e0c58aa-242d-4c9f-bbcb-8a814e19cc30","version":3} \ No newline at end of file diff --git a/e2e/chains/bsc/validators/keystore/bsc-validator3 b/e2e/chains/bsc/validators/keystore/bsc-validator3 new file mode 100644 index 0000000..d3cad63 --- /dev/null +++ b/e2e/chains/bsc/validators/keystore/bsc-validator3 @@ -0,0 +1 @@ +{"address":"8fdaaa7e6631e438625ca25c857a3727ea28e565","crypto":{"cipher":"aes-128-ctr","ciphertext":"6a61423fc5f39a7b999083dc123e6e7b514dd11c35dae817074a0a0da3b0943e","cipherparams":{"iv":"dd532308dee87c8c9830b0879b8bb254"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"17b6fadf866bab1f893979be86e8c53044e0f8d9038957a86d7d65b2ba687fd7"},"mac":"2b88b55a0cc32f65f9a13a36de7b312c64db2af6149fe9e8a46463106db298e3"},"id":"0d6e634c-12d8-4fa0-8a45-7e9a344073fa","version":3} \ No newline at end of file diff --git a/e2e/chains/bsc/validators/keystore/bsc-validator4 b/e2e/chains/bsc/validators/keystore/bsc-validator4 new file mode 100644 index 0000000..fb3d41e --- /dev/null +++ b/e2e/chains/bsc/validators/keystore/bsc-validator4 @@ -0,0 +1 @@ +{"address":"e04db2de85453e0936b441c339a26d10cfa71b50","crypto":{"cipher":"aes-128-ctr","ciphertext":"6e44e73d78d6500f51251e2ceffbdf894a859a9095425632ba2c1292c42275aa","cipherparams":{"iv":"1bb72eb3157af6410280ab713376cf21"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"cb207713ecf10f2b4eb904874931d9dac1e19f7eeb19919ff262d16dfa4201db"},"mac":"8d17848a7b39cda2e47ac30f192b67366b1d4a498356398efb1cac59e7d34ec7"},"id":"802babd1-e7ae-48cb-8c1d-81a53d93cca4","version":3} \ No newline at end of file diff --git a/e2e/chains/bsc/validators/keystore/bsc-validator5 b/e2e/chains/bsc/validators/keystore/bsc-validator5 new file mode 100644 index 0000000..d491fee --- /dev/null +++ b/e2e/chains/bsc/validators/keystore/bsc-validator5 @@ -0,0 +1 @@ +{"address":"b2e42bc54d19116d2348ac83461e2e0915d508ad","crypto":{"cipher":"aes-128-ctr","ciphertext":"fd4534942cbaab9b8b33d7200ca298655aff027d9094c89ac545cc8d805c462f","cipherparams":{"iv":"2920c51a0e3eb658089d9b6569beebdb"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"d1a1a404398a2462e620411d9cc813a02f8f8b58b09f33415597cb1086090d49"},"mac":"61dc09e39a27a78ad36c07f84e305c40a46d75628e61d16d68b31a503661ebd9"},"id":"913c87e4-0a12-45a8-8c96-fe6163e3a6f3","version":3} \ No newline at end of file diff --git a/e2e/contracts/contracts/clients/ParliaClient.sol b/e2e/contracts/contracts/clients/ParliaClient.sol index ae580de..3d9f3a9 100755 --- a/e2e/contracts/contracts/clients/ParliaClient.sol +++ b/e2e/contracts/contracts/clients/ParliaClient.sol @@ -248,7 +248,7 @@ contract ParliaClient is ILightClient { Any.Data memory any = Any.decode(bz); require(keccak256(abi.encodePacked(any.type_url)) == HEADER_TYPE_URL_HASH, "invalid header type"); Header.Data memory header = Header.decode(any.value); - bytes memory rlpEthHeader = header.headers[0].header; + bytes memory rlpEthHeader = header.target.header; RLPReader.RLPItem[] memory items = rlpEthHeader.toRlpItem().toList(); Height.Data memory height = Height.Data({revision_number: 0, revision_height: uint64(items[8].toUint())}); diff --git a/e2e/contracts/contracts/ibc/lightclients/parlia/v1/parlia.sol b/e2e/contracts/contracts/ibc/lightclients/parlia/v1/parlia.sol index 7b6c303..54b424b 100644 --- a/e2e/contracts/contracts/ibc/lightclients/parlia/v1/parlia.sol +++ b/e2e/contracts/contracts/ibc/lightclients/parlia/v1/parlia.sol @@ -4,264 +4,6 @@ import "@hyperledger-labs/yui-ibc-solidity/contracts/proto/ProtoBufRuntime.sol"; import "@hyperledger-labs/yui-ibc-solidity/contracts/proto/GoogleProtobufAny.sol"; import "../../../core/client/v1/client.sol"; -library IbcLightclientsParliaV1Fraction { - - - //struct definition - struct Data { - uint64 numerator; - uint64 denominator; - } - - // Decoder section - - /** - * @dev The main decoder for memory - * @param bs The bytes array to be decoded - * @return The decoded struct - */ - function decode(bytes memory bs) internal pure returns (Data memory) { - (Data memory x, ) = _decode(32, bs, bs.length); - return x; - } - - /** - * @dev The main decoder for storage - * @param self The in-storage struct - * @param bs The bytes array to be decoded - */ - function decode(Data storage self, bytes memory bs) internal { - (Data memory x, ) = _decode(32, bs, bs.length); - store(x, self); - } - // inner decoder - - /** - * @dev The decoder for internal usage - * @param p The offset of bytes array to start decode - * @param bs The bytes array to be decoded - * @param sz The number of bytes expected - * @return The decoded struct - * @return The number of bytes decoded - */ - function _decode(uint256 p, bytes memory bs, uint256 sz) - internal - pure - returns (Data memory, uint) - { - Data memory r; - uint256 fieldId; - ProtoBufRuntime.WireType wireType; - uint256 bytesRead; - uint256 offset = p; - uint256 pointer = p; - while (pointer < offset + sz) { - (fieldId, wireType, bytesRead) = ProtoBufRuntime._decode_key(pointer, bs); - pointer += bytesRead; - if (fieldId == 1) { - pointer += _read_numerator(pointer, bs, r); - } else - if (fieldId == 2) { - pointer += _read_denominator(pointer, bs, r); - } else - { - pointer += ProtoBufRuntime._skip_field_decode(wireType, pointer, bs); - } - - } - return (r, sz); - } - - // field readers - - /** - * @dev The decoder for reading a field - * @param p The offset of bytes array to start decode - * @param bs The bytes array to be decoded - * @param r The in-memory struct - * @return The number of bytes decoded - */ - function _read_numerator( - uint256 p, - bytes memory bs, - Data memory r - ) internal pure returns (uint) { - (uint64 x, uint256 sz) = ProtoBufRuntime._decode_uint64(p, bs); - r.numerator = x; - return sz; - } - - /** - * @dev The decoder for reading a field - * @param p The offset of bytes array to start decode - * @param bs The bytes array to be decoded - * @param r The in-memory struct - * @return The number of bytes decoded - */ - function _read_denominator( - uint256 p, - bytes memory bs, - Data memory r - ) internal pure returns (uint) { - (uint64 x, uint256 sz) = ProtoBufRuntime._decode_uint64(p, bs); - r.denominator = x; - return sz; - } - - - // Encoder section - - /** - * @dev The main encoder for memory - * @param r The struct to be encoded - * @return The encoded byte array - */ - function encode(Data memory r) internal pure returns (bytes memory) { - bytes memory bs = new bytes(_estimate(r)); - uint256 sz = _encode(r, 32, bs); - assembly { - mstore(bs, sz) - } - return bs; - } - // inner encoder - - /** - * @dev The encoder for internal usage - * @param r The struct to be encoded - * @param p The offset of bytes array to start decode - * @param bs The bytes array to be decoded - * @return The number of bytes encoded - */ - function _encode(Data memory r, uint256 p, bytes memory bs) - internal - pure - returns (uint) - { - uint256 offset = p; - uint256 pointer = p; - - if (r.numerator != 0) { - pointer += ProtoBufRuntime._encode_key( - 1, - ProtoBufRuntime.WireType.Varint, - pointer, - bs - ); - pointer += ProtoBufRuntime._encode_uint64(r.numerator, pointer, bs); - } - if (r.denominator != 0) { - pointer += ProtoBufRuntime._encode_key( - 2, - ProtoBufRuntime.WireType.Varint, - pointer, - bs - ); - pointer += ProtoBufRuntime._encode_uint64(r.denominator, pointer, bs); - } - return pointer - offset; - } - // nested encoder - - /** - * @dev The encoder for inner struct - * @param r The struct to be encoded - * @param p The offset of bytes array to start decode - * @param bs The bytes array to be decoded - * @return The number of bytes encoded - */ - function _encode_nested(Data memory r, uint256 p, bytes memory bs) - internal - pure - returns (uint) - { - /** - * First encoded `r` into a temporary array, and encode the actual size used. - * Then copy the temporary array into `bs`. - */ - uint256 offset = p; - uint256 pointer = p; - bytes memory tmp = new bytes(_estimate(r)); - uint256 tmpAddr = ProtoBufRuntime.getMemoryAddress(tmp); - uint256 bsAddr = ProtoBufRuntime.getMemoryAddress(bs); - uint256 size = _encode(r, 32, tmp); - pointer += ProtoBufRuntime._encode_varint(size, pointer, bs); - ProtoBufRuntime.copyBytes(tmpAddr + 32, bsAddr + pointer, size); - pointer += size; - delete tmp; - return pointer - offset; - } - // estimator - - /** - * @dev The estimator for a struct - * @param r The struct to be encoded - * @return The number of bytes encoded in estimation - */ - function _estimate( - Data memory r - ) internal pure returns (uint) { - uint256 e; - e += 1 + ProtoBufRuntime._sz_uint64(r.numerator); - e += 1 + ProtoBufRuntime._sz_uint64(r.denominator); - return e; - } - // empty checker - - function _empty( - Data memory r - ) internal pure returns (bool) { - - if (r.numerator != 0) { - return false; - } - - if (r.denominator != 0) { - return false; - } - - return true; - } - - - //store function - /** - * @dev Store in-memory struct to storage - * @param input The in-memory struct - * @param output The in-storage struct - */ - function store(Data memory input, Data storage output) internal { - output.numerator = input.numerator; - output.denominator = input.denominator; - - } - - - - //utility functions - /** - * @dev Return an empty struct - * @return r The empty struct - */ - function nil() internal pure returns (Data memory r) { - assembly { - r := 0 - } - } - - /** - * @dev Test whether a struct is empty - * @param x The struct to be tested - * @return r True if it is empty - */ - function isNil(Data memory x) internal pure returns (bool r) { - assembly { - r := iszero(x) - } - } -} -//library IbcLightclientsParliaV1Fraction - library IbcLightclientsParliaV1ClientState { @@ -271,7 +13,6 @@ library IbcLightclientsParliaV1ClientState { bytes ibc_store_address; bytes ibc_commitments_slot; IbcCoreClientV1Height.Data latest_height; - IbcLightclientsParliaV1Fraction.Data trust_level; uint64 trusting_period; bool frozen; } @@ -333,9 +74,6 @@ library IbcLightclientsParliaV1ClientState { if (fieldId == 4) { pointer += _read_latest_height(pointer, bs, r); } else - if (fieldId == 5) { - pointer += _read_trust_level(pointer, bs, r); - } else if (fieldId == 6) { pointer += _read_trusting_period(pointer, bs, r); } else @@ -420,23 +158,6 @@ library IbcLightclientsParliaV1ClientState { return sz; } - /** - * @dev The decoder for reading a field - * @param p The offset of bytes array to start decode - * @param bs The bytes array to be decoded - * @param r The in-memory struct - * @return The number of bytes decoded - */ - function _read_trust_level( - uint256 p, - bytes memory bs, - Data memory r - ) internal pure returns (uint) { - (IbcLightclientsParliaV1Fraction.Data memory x, uint256 sz) = _decode_IbcLightclientsParliaV1Fraction(p, bs); - r.trust_level = x; - return sz; - } - /** * @dev The decoder for reading a field * @param p The offset of bytes array to start decode @@ -491,25 +212,6 @@ library IbcLightclientsParliaV1ClientState { return (r, sz + bytesRead); } - /** - * @dev The decoder for reading a inner struct field - * @param p The offset of bytes array to start decode - * @param bs The bytes array to be decoded - * @return The decoded inner-struct - * @return The number of bytes used to decode - */ - function _decode_IbcLightclientsParliaV1Fraction(uint256 p, bytes memory bs) - internal - pure - returns (IbcLightclientsParliaV1Fraction.Data memory, uint) - { - uint256 pointer = p; - (uint256 sz, uint256 bytesRead) = ProtoBufRuntime._decode_varint(pointer, bs); - pointer += bytesRead; - (IbcLightclientsParliaV1Fraction.Data memory r, ) = IbcLightclientsParliaV1Fraction._decode(pointer, bs, sz); - return (r, sz + bytesRead); - } - // Encoder section @@ -579,15 +281,6 @@ library IbcLightclientsParliaV1ClientState { ); pointer += IbcCoreClientV1Height._encode_nested(r.latest_height, pointer, bs); - - pointer += ProtoBufRuntime._encode_key( - 5, - ProtoBufRuntime.WireType.LengthDelim, - pointer, - bs - ); - pointer += IbcLightclientsParliaV1Fraction._encode_nested(r.trust_level, pointer, bs); - if (r.trusting_period != 0) { pointer += ProtoBufRuntime._encode_key( 6, @@ -653,7 +346,6 @@ library IbcLightclientsParliaV1ClientState { e += 1 + ProtoBufRuntime._sz_lendelim(r.ibc_store_address.length); e += 1 + ProtoBufRuntime._sz_lendelim(r.ibc_commitments_slot.length); e += 1 + ProtoBufRuntime._sz_lendelim(IbcCoreClientV1Height._estimate(r.latest_height)); - e += 1 + ProtoBufRuntime._sz_lendelim(IbcLightclientsParliaV1Fraction._estimate(r.trust_level)); e += 1 + ProtoBufRuntime._sz_uint64(r.trusting_period); e += 1 + 1; return e; @@ -699,7 +391,6 @@ library IbcLightclientsParliaV1ClientState { output.ibc_store_address = input.ibc_store_address; output.ibc_commitments_slot = input.ibc_commitments_slot; IbcCoreClientV1Height.store(input.latest_height, output.latest_height); - IbcLightclientsParliaV1Fraction.store(input.trust_level, output.trust_level); output.trusting_period = input.trusting_period; output.frozen = input.frozen; @@ -958,11 +649,12 @@ library IbcLightclientsParliaV1Header { //struct definition struct Data { - IbcLightclientsParliaV1ETHHeader.Data[] headers; + IbcLightclientsParliaV1ETHHeader.Data target; + IbcLightclientsParliaV1ETHHeader.Data parent; IbcCoreClientV1Height.Data trusted_height; bytes account_proof; - bytes[] previous_validators; - bytes[] current_validators; + bytes[] parent_validators; + bytes[] target_validators; } // Decoder section @@ -1002,7 +694,7 @@ library IbcLightclientsParliaV1Header { returns (Data memory, uint) { Data memory r; - uint[6] memory counters; + uint[7] memory counters; uint256 fieldId; ProtoBufRuntime.WireType wireType; uint256 bytesRead; @@ -1012,19 +704,22 @@ library IbcLightclientsParliaV1Header { (fieldId, wireType, bytesRead) = ProtoBufRuntime._decode_key(pointer, bs); pointer += bytesRead; if (fieldId == 1) { - pointer += _read_unpacked_repeated_headers(pointer, bs, nil(), counters); + pointer += _read_target(pointer, bs, r); } else if (fieldId == 2) { - pointer += _read_trusted_height(pointer, bs, r); + pointer += _read_parent(pointer, bs, r); } else if (fieldId == 3) { - pointer += _read_account_proof(pointer, bs, r); + pointer += _read_trusted_height(pointer, bs, r); } else if (fieldId == 4) { - pointer += _read_unpacked_repeated_previous_validators(pointer, bs, nil(), counters); + pointer += _read_account_proof(pointer, bs, r); } else if (fieldId == 5) { - pointer += _read_unpacked_repeated_current_validators(pointer, bs, nil(), counters); + pointer += _read_unpacked_repeated_parent_validators(pointer, bs, nil(), counters); + } else + if (fieldId == 6) { + pointer += _read_unpacked_repeated_target_validators(pointer, bs, nil(), counters); } else { pointer += ProtoBufRuntime._skip_field_decode(wireType, pointer, bs); @@ -1032,30 +727,23 @@ library IbcLightclientsParliaV1Header { } pointer = offset; - if (counters[1] > 0) { - require(r.headers.length == 0); - r.headers = new IbcLightclientsParliaV1ETHHeader.Data[](counters[1]); - } - if (counters[4] > 0) { - require(r.previous_validators.length == 0); - r.previous_validators = new bytes[](counters[4]); - } if (counters[5] > 0) { - require(r.current_validators.length == 0); - r.current_validators = new bytes[](counters[5]); + require(r.parent_validators.length == 0); + r.parent_validators = new bytes[](counters[5]); + } + if (counters[6] > 0) { + require(r.target_validators.length == 0); + r.target_validators = new bytes[](counters[6]); } while (pointer < offset + sz) { (fieldId, wireType, bytesRead) = ProtoBufRuntime._decode_key(pointer, bs); pointer += bytesRead; - if (fieldId == 1) { - pointer += _read_unpacked_repeated_headers(pointer, bs, r, counters); - } else - if (fieldId == 4) { - pointer += _read_unpacked_repeated_previous_validators(pointer, bs, r, counters); - } else if (fieldId == 5) { - pointer += _read_unpacked_repeated_current_validators(pointer, bs, r, counters); + pointer += _read_unpacked_repeated_parent_validators(pointer, bs, r, counters); + } else + if (fieldId == 6) { + pointer += _read_unpacked_repeated_target_validators(pointer, bs, r, counters); } else { pointer += ProtoBufRuntime._skip_field_decode(wireType, pointer, bs); @@ -1071,25 +759,32 @@ library IbcLightclientsParliaV1Header { * @param p The offset of bytes array to start decode * @param bs The bytes array to be decoded * @param r The in-memory struct - * @param counters The counters for repeated fields * @return The number of bytes decoded */ - function _read_unpacked_repeated_headers( + function _read_target( uint256 p, bytes memory bs, - Data memory r, - uint[6] memory counters + Data memory r ) internal pure returns (uint) { - /** - * if `r` is NULL, then only counting the number of fields. - */ (IbcLightclientsParliaV1ETHHeader.Data memory x, uint256 sz) = _decode_IbcLightclientsParliaV1ETHHeader(p, bs); - if (isNil(r)) { - counters[1] += 1; - } else { - r.headers[r.headers.length - counters[1]] = x; - counters[1] -= 1; - } + r.target = x; + return sz; + } + + /** + * @dev The decoder for reading a field + * @param p The offset of bytes array to start decode + * @param bs The bytes array to be decoded + * @param r The in-memory struct + * @return The number of bytes decoded + */ + function _read_parent( + uint256 p, + bytes memory bs, + Data memory r + ) internal pure returns (uint) { + (IbcLightclientsParliaV1ETHHeader.Data memory x, uint256 sz) = _decode_IbcLightclientsParliaV1ETHHeader(p, bs); + r.parent = x; return sz; } @@ -1135,21 +830,21 @@ library IbcLightclientsParliaV1Header { * @param counters The counters for repeated fields * @return The number of bytes decoded */ - function _read_unpacked_repeated_previous_validators( + function _read_unpacked_repeated_parent_validators( uint256 p, bytes memory bs, Data memory r, - uint[6] memory counters + uint[7] memory counters ) internal pure returns (uint) { /** * if `r` is NULL, then only counting the number of fields. */ (bytes memory x, uint256 sz) = ProtoBufRuntime._decode_bytes(p, bs); if (isNil(r)) { - counters[4] += 1; + counters[5] += 1; } else { - r.previous_validators[r.previous_validators.length - counters[4]] = x; - counters[4] -= 1; + r.parent_validators[r.parent_validators.length - counters[5]] = x; + counters[5] -= 1; } return sz; } @@ -1162,21 +857,21 @@ library IbcLightclientsParliaV1Header { * @param counters The counters for repeated fields * @return The number of bytes decoded */ - function _read_unpacked_repeated_current_validators( + function _read_unpacked_repeated_target_validators( uint256 p, bytes memory bs, Data memory r, - uint[6] memory counters + uint[7] memory counters ) internal pure returns (uint) { /** * if `r` is NULL, then only counting the number of fields. */ (bytes memory x, uint256 sz) = ProtoBufRuntime._decode_bytes(p, bs); if (isNil(r)) { - counters[5] += 1; + counters[6] += 1; } else { - r.current_validators[r.current_validators.length - counters[5]] = x; - counters[5] -= 1; + r.target_validators[r.target_validators.length - counters[6]] = x; + counters[6] -= 1; } return sz; } @@ -1253,17 +948,15 @@ library IbcLightclientsParliaV1Header { uint256 offset = p; uint256 pointer = p; uint256 i; - if (r.headers.length != 0) { - for(i = 0; i < r.headers.length; i++) { - pointer += ProtoBufRuntime._encode_key( - 1, - ProtoBufRuntime.WireType.LengthDelim, - pointer, - bs) - ; - pointer += IbcLightclientsParliaV1ETHHeader._encode_nested(r.headers[i], pointer, bs); - } - } + + pointer += ProtoBufRuntime._encode_key( + 1, + ProtoBufRuntime.WireType.LengthDelim, + pointer, + bs + ); + pointer += IbcLightclientsParliaV1ETHHeader._encode_nested(r.target, pointer, bs); + pointer += ProtoBufRuntime._encode_key( 2, @@ -1271,37 +964,46 @@ library IbcLightclientsParliaV1Header { pointer, bs ); + pointer += IbcLightclientsParliaV1ETHHeader._encode_nested(r.parent, pointer, bs); + + + pointer += ProtoBufRuntime._encode_key( + 3, + ProtoBufRuntime.WireType.LengthDelim, + pointer, + bs + ); pointer += IbcCoreClientV1Height._encode_nested(r.trusted_height, pointer, bs); if (r.account_proof.length != 0) { pointer += ProtoBufRuntime._encode_key( - 3, + 4, ProtoBufRuntime.WireType.LengthDelim, pointer, bs ); pointer += ProtoBufRuntime._encode_bytes(r.account_proof, pointer, bs); } - if (r.previous_validators.length != 0) { - for(i = 0; i < r.previous_validators.length; i++) { + if (r.parent_validators.length != 0) { + for(i = 0; i < r.parent_validators.length; i++) { pointer += ProtoBufRuntime._encode_key( - 4, + 5, ProtoBufRuntime.WireType.LengthDelim, pointer, bs) ; - pointer += ProtoBufRuntime._encode_bytes(r.previous_validators[i], pointer, bs); + pointer += ProtoBufRuntime._encode_bytes(r.parent_validators[i], pointer, bs); } } - if (r.current_validators.length != 0) { - for(i = 0; i < r.current_validators.length; i++) { + if (r.target_validators.length != 0) { + for(i = 0; i < r.target_validators.length; i++) { pointer += ProtoBufRuntime._encode_key( - 5, + 6, ProtoBufRuntime.WireType.LengthDelim, pointer, bs) ; - pointer += ProtoBufRuntime._encode_bytes(r.current_validators[i], pointer, bs); + pointer += ProtoBufRuntime._encode_bytes(r.target_validators[i], pointer, bs); } } return pointer - offset; @@ -1347,16 +1049,15 @@ library IbcLightclientsParliaV1Header { Data memory r ) internal pure returns (uint) { uint256 e;uint256 i; - for(i = 0; i < r.headers.length; i++) { - e += 1 + ProtoBufRuntime._sz_lendelim(IbcLightclientsParliaV1ETHHeader._estimate(r.headers[i])); - } + e += 1 + ProtoBufRuntime._sz_lendelim(IbcLightclientsParliaV1ETHHeader._estimate(r.target)); + e += 1 + ProtoBufRuntime._sz_lendelim(IbcLightclientsParliaV1ETHHeader._estimate(r.parent)); e += 1 + ProtoBufRuntime._sz_lendelim(IbcCoreClientV1Height._estimate(r.trusted_height)); e += 1 + ProtoBufRuntime._sz_lendelim(r.account_proof.length); - for(i = 0; i < r.previous_validators.length; i++) { - e += 1 + ProtoBufRuntime._sz_lendelim(r.previous_validators[i].length); + for(i = 0; i < r.parent_validators.length; i++) { + e += 1 + ProtoBufRuntime._sz_lendelim(r.parent_validators[i].length); } - for(i = 0; i < r.current_validators.length; i++) { - e += 1 + ProtoBufRuntime._sz_lendelim(r.current_validators[i].length); + for(i = 0; i < r.target_validators.length; i++) { + e += 1 + ProtoBufRuntime._sz_lendelim(r.target_validators[i].length); } return e; } @@ -1366,19 +1067,15 @@ library IbcLightclientsParliaV1Header { Data memory r ) internal pure returns (bool) { - if (r.headers.length != 0) { - return false; - } - if (r.account_proof.length != 0) { return false; } - if (r.previous_validators.length != 0) { + if (r.parent_validators.length != 0) { return false; } - if (r.current_validators.length != 0) { + if (r.target_validators.length != 0) { return false; } @@ -1393,71 +1090,50 @@ library IbcLightclientsParliaV1Header { * @param output The in-storage struct */ function store(Data memory input, Data storage output) internal { - - for(uint256 i1 = 0; i1 < input.headers.length; i1++) { - output.headers.push(input.headers[i1]); - } - + IbcLightclientsParliaV1ETHHeader.store(input.target, output.target); + IbcLightclientsParliaV1ETHHeader.store(input.parent, output.parent); IbcCoreClientV1Height.store(input.trusted_height, output.trusted_height); output.account_proof = input.account_proof; - output.previous_validators = input.previous_validators; - output.current_validators = input.current_validators; + output.parent_validators = input.parent_validators; + output.target_validators = input.target_validators; } - //array helpers for Headers - /** - * @dev Add value to an array - * @param self The in-memory struct - * @param value The value to add - */ - function addHeaders(Data memory self, IbcLightclientsParliaV1ETHHeader.Data memory value) internal pure { - /** - * First resize the array. Then add the new element to the end. - */ - IbcLightclientsParliaV1ETHHeader.Data[] memory tmp = new IbcLightclientsParliaV1ETHHeader.Data[](self.headers.length + 1); - for (uint256 i = 0; i < self.headers.length; i++) { - tmp[i] = self.headers[i]; - } - tmp[self.headers.length] = value; - self.headers = tmp; - } - - //array helpers for PreviousValidators + //array helpers for ParentValidators /** * @dev Add value to an array * @param self The in-memory struct * @param value The value to add */ - function addPreviousValidators(Data memory self, bytes memory value) internal pure { + function addParentValidators(Data memory self, bytes memory value) internal pure { /** * First resize the array. Then add the new element to the end. */ - bytes[] memory tmp = new bytes[](self.previous_validators.length + 1); - for (uint256 i = 0; i < self.previous_validators.length; i++) { - tmp[i] = self.previous_validators[i]; + bytes[] memory tmp = new bytes[](self.parent_validators.length + 1); + for (uint256 i = 0; i < self.parent_validators.length; i++) { + tmp[i] = self.parent_validators[i]; } - tmp[self.previous_validators.length] = value; - self.previous_validators = tmp; + tmp[self.parent_validators.length] = value; + self.parent_validators = tmp; } - //array helpers for CurrentValidators + //array helpers for TargetValidators /** * @dev Add value to an array * @param self The in-memory struct * @param value The value to add */ - function addCurrentValidators(Data memory self, bytes memory value) internal pure { + function addTargetValidators(Data memory self, bytes memory value) internal pure { /** * First resize the array. Then add the new element to the end. */ - bytes[] memory tmp = new bytes[](self.current_validators.length + 1); - for (uint256 i = 0; i < self.current_validators.length; i++) { - tmp[i] = self.current_validators[i]; + bytes[] memory tmp = new bytes[](self.target_validators.length + 1); + for (uint256 i = 0; i < self.target_validators.length; i++) { + tmp[i] = self.target_validators[i]; } - tmp[self.current_validators.length] = value; - self.current_validators = tmp; + tmp[self.target_validators.length] = value; + self.target_validators = tmp; } diff --git a/e2e/contracts/package-lock.json b/e2e/contracts/package-lock.json index d0f5aae..0afe436 100644 --- a/e2e/contracts/package-lock.json +++ b/e2e/contracts/package-lock.json @@ -2536,6 +2536,7 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/abstract-leveldown/-/abstract-leveldown-7.2.0.tgz", "integrity": "sha512-DnhQwcFEaYsvYDnACLZhMmCWd3rkOeEvglpa4q5i/5Jlm3UIsWaxVzuXvDLFCSCWRO3yy2/+V/G7FusFgejnfQ==", + "optional": true, "dependencies": { "buffer": "^6.0.3", "catering": "^2.0.0", @@ -3434,6 +3435,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/catering/-/catering-2.1.1.tgz", "integrity": "sha512-K7Qy8O9p76sL3/3m7/zLKbRkyOlSZAgzEaLhyj2mXS8PsCud2Eo4hAb8aLtZqHh0QGqLcb9dlJSu6lHRVENm1w==", + "optional": true, "engines": { "node": ">=6" } @@ -4179,6 +4181,7 @@ "version": "0.4.1", "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.4.1.tgz", "integrity": "sha512-r4eRSeStEGf6M5SKdrQhhLK5bOwOBxQhIE3YSTnZE3GpKiLfnnhE+tPtrJE79+eDJgm39BM6LSoI8SCx4HbwlQ==", + "optional": true, "engines": { "node": ">=6" } @@ -5657,7 +5660,6 @@ "version": "4.0.5", "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.5.tgz", "integrity": "sha512-HTm14iMQKK2FjFLRTM5lAVcyaUzOnqbPtesFIvREgXpJHdQm8bWS+GkQgIkfaBYRHuCnea7w8UVNfwiAQhlr9A==", - "hasInstallScript": true, "optional": true, "dependencies": { "node-gyp-build": "^4.3.0" @@ -5987,7 +5989,6 @@ "version": "5.0.7", "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.7.tgz", "integrity": "sha512-vLt1O5Pp+flcArHGIyKEQq883nBt8nN8tVBcoL0qUXj2XT1n7p70yGIq2VK98I5FdZ1YHc0wk/koOnHjnXWk1Q==", - "hasInstallScript": true, "optional": true, "dependencies": { "node-gyp-build": "^4.3.0" @@ -6515,6 +6516,7 @@ "url": "https://feross.org/support" } ], + "optional": true, "engines": { "node": ">=4" } @@ -6957,6 +6959,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/level-concat-iterator/-/level-concat-iterator-3.1.0.tgz", "integrity": "sha512-BWRCMHBxbIqPxJ8vHOvKUsaO0v1sLYZtjN3K2iZJsRBYtp+ONsY6Jfi6hy9K3+zolgQRryhIn2NRZjZnWJ9NmQ==", + "optional": true, "dependencies": { "catering": "^2.1.0" }, @@ -7080,6 +7083,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/level-supports/-/level-supports-2.1.0.tgz", "integrity": "sha512-E486g1NCjW5cF78KGPrMDRBYzPuueMZ6VBXHT6gC7A8UYWGiM14fGgp+s/L1oFfDWSPV/+SFkYCmZ0SiESkRKA==", + "optional": true, "engines": { "node": ">=10" } @@ -7134,6 +7138,7 @@ "resolved": "https://registry.npmjs.org/leveldown/-/leveldown-5.6.0.tgz", "integrity": "sha512-iB8O/7Db9lPaITU1aA2txU/cBEXAt4vWwKQRrrWuS6XDgbP4QZGj9BL2aNbwb002atoQ/lIotJkfyzz+ygQnUQ==", "hasInstallScript": true, + "optional": true, "dependencies": { "abstract-leveldown": "~6.2.1", "napi-macros": "~2.0.0", @@ -7147,6 +7152,7 @@ "version": "6.2.3", "resolved": "https://registry.npmjs.org/abstract-leveldown/-/abstract-leveldown-6.2.3.tgz", "integrity": "sha512-BsLm5vFMRUrrLeCcRc+G0t2qOaTzpoJQLOubq2XM72eNpjF5UdU5o/5NvlNhx95XHcAvcl8OMXr4mlg/fRgUXQ==", + "optional": true, "dependencies": { "buffer": "^5.5.0", "immediate": "^3.2.3", @@ -7176,6 +7182,7 @@ "url": "https://feross.org/support" } ], + "optional": true, "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" @@ -7185,6 +7192,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/level-concat-iterator/-/level-concat-iterator-2.0.1.tgz", "integrity": "sha512-OTKKOqeav2QWcERMJR7IS9CUo1sHnke2C0gkSmcR7QuEtFNLLzHQAvnMw8ykvEcv0Qtkg0p7FOwP1v9e5Smdcw==", + "optional": true, "engines": { "node": ">=6" } @@ -7193,6 +7201,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/level-supports/-/level-supports-1.0.1.tgz", "integrity": "sha512-rXM7GYnW8gsl1vedTJIbzOrRv85c/2uCMpiiCzO2fndd06U/kUXEEU9evYn4zFggBOg36IsBW8LzqIpETwwQzg==", + "optional": true, "dependencies": { "xtend": "^4.0.2" }, @@ -7204,6 +7213,7 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.1.1.tgz", "integrity": "sha512-dSq1xmcPDKPZ2EED2S6zw/b9NKsqzXRE6dVr8TVQnI3FJOTteUMuqF3Qqs6LZg+mLGYJWqQzMbIjMtJqTv87nQ==", + "optional": true, "bin": { "node-gyp-build": "bin.js", "node-gyp-build-optional": "optional.js", @@ -7990,7 +8000,8 @@ "node_modules/napi-macros": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/napi-macros/-/napi-macros-2.0.0.tgz", - "integrity": "sha512-A0xLykHtARfueITVDernsAWdtIMbOJgKgcluwENp3AlsKN/PloyO10HtmoqnFAQAcxPkgZN7wdfPfEd0zNGxbg==" + "integrity": "sha512-A0xLykHtARfueITVDernsAWdtIMbOJgKgcluwENp3AlsKN/PloyO10HtmoqnFAQAcxPkgZN7wdfPfEd0zNGxbg==", + "optional": true }, "node_modules/negotiator": { "version": "0.6.3", @@ -8973,7 +8984,8 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "optional": true }, "node_modules/quick-lru": { "version": "5.1.1", diff --git a/module/header.go b/module/header.go index 1086265..82403c3 100644 --- a/module/header.go +++ b/module/header.go @@ -13,7 +13,6 @@ import ( const extraVanity = 32 const extraSeal = 65 -const validatorBytesLengthBeforeLuban = 20 const validatorBytesLength = 68 // Parlia TODO client_type @@ -69,7 +68,7 @@ func (h *Header) Account(path common.Address) (*types.StateAccount, error) { return verifyAccount(target, h.AccountProof, path) } -func extractValidatorSet(h *types.Header) ([][]byte, error) { +func ExtractValidatorSet(h *types.Header) ([][]byte, error) { extra := h.Extra if len(extra) < extraVanity+extraSeal { return nil, fmt.Errorf("invalid extra length : %d", h.Number.Uint64()) diff --git a/module/header_test.go b/module/header_test.go index 5532696..ead6b37 100644 --- a/module/header_test.go +++ b/module/header_test.go @@ -46,7 +46,7 @@ func (ts *HeaderTestSuite) TestNewHeaderSuccess() { target, err := header.DecodedTarget() ts.Require().NoError(err) ts.Require().Equal(target.Number, rawHeader.Number) - validator, err := extractValidatorSet(target) + validator, err := ExtractValidatorSet(target) ts.Require().NoError(err) ts.Require().Equal(len(validator), 21) ts.Require().NoError(header.ValidateBasic()) @@ -65,16 +65,16 @@ func (ts *HeaderTestSuite) TestExtractValidatorSet() { Number: big.NewInt(29835600), Extra: common.Hex2Bytes("d883010202846765746888676f312e31392e39856c696e7578000000110bea95071284214b9b9c85549ab3d2b972df0deef66ac2c9ab1757500d6f4fdee439b17cf8e43267f94bc759162fb68de676d2fe10cc4cde26dd06be7e345e9cbf4b1dbf86b262bc35552c16704d214347f29fa77f77da6d75d7c752b742ad4855bae330426b823e742da31f816cc83bc16d69a9134be0cfb4a1d17ec34f1b5b32d5c20440b8536b1e88f0f296c5d20b2a975c050e4220be276ace4892f4b41a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000980a75ecd1309ea12fa2ed87a8744fbfc9b863d589037a9ace3b590165ea1c0c5ac72bf600b7c88c1e435f41932c1132aae1bfa0bb68e46b96ccb12c3415e4d82af717d8a2959d3f95eae5dc7d70144ce1b73b403b7eb6e0b973c2d38487e58fd6e145491b110080fb14ac915a0411fc78f19e09a399ddee0d20c63a75d8f930f1694544ad2dc01bb71b214cb885500844365e95cd9942c7276e7fd8a2750ec6dded3dcdc2f351782310b0eadc077db59abca0f0cd26776e2e7acb9f3bce40b1fa5221fd1561226c6263cc5ff474cf03cceff28abc65c9cbae594f725c80e12d96c9b86c3400e529bfe184056e257c07940bb664636f689e8d2027c834681f8f878b73445261034e946bb2d901b4b878f8b27bb860a140cc9c8cc07d4ddf366440d9784efc88743d26af40f8956dd1c3501e560f745910bb14a5ec392f53cf78ddc2d2d69a146af287f7e079c3cbbfd3d446836d9b9397aa9a803b6c6b4f1cfc50baddbe2378cf194da35b9f4a1a32850114f1c5d9f84c8401c7414ea049d2e0876f51ce4693892331f8344a102aad88eb9e9bcfaa247cc9f898d1f8008401c7414fa0cf8d34727ff1d895bb49ca4be60c3b24d98d8afa9ce78644924e4b9aa39df8548022dc981e8703d3ca8b23fc032089667cb631cb28c32731762813bbf9fdb7e7a56b3945d65f2d72402a2abb9fbaf4bf094a3e5a542e175ecc54b426ee366b2ba200"), } - validators, err := extractValidatorSet(testnetHeader) + validators, err := ExtractValidatorSet(testnetHeader) ts.Require().NoError(err) ts.Require().Len(validators, 7) - ts.Require().Equal(common.Bytes2Hex(validators[0]), "1284214b9b9c85549ab3d2b972df0deef66ac2c9") - ts.Require().Equal(common.Bytes2Hex(validators[1]), "35552c16704d214347f29fa77f77da6d75d7c752") - ts.Require().Equal(common.Bytes2Hex(validators[2]), "96c5d20b2a975c050e4220be276ace4892f4b41a") - ts.Require().Equal(common.Bytes2Hex(validators[3]), "980a75ecd1309ea12fa2ed87a8744fbfc9b863d5") - ts.Require().Equal(common.Bytes2Hex(validators[4]), "a2959d3f95eae5dc7d70144ce1b73b403b7eb6e0") - ts.Require().Equal(common.Bytes2Hex(validators[5]), "b71b214cb885500844365e95cd9942c7276e7fd8") - ts.Require().Equal(common.Bytes2Hex(validators[6]), "f474cf03cceff28abc65c9cbae594f725c80e12d") + ts.Require().Equal(common.Bytes2Hex(validators[0]), "1284214b9b9c85549ab3d2b972df0deef66ac2c9ab1757500d6f4fdee439b17cf8e43267f94bc759162fb68de676d2fe10cc4cde26dd06be7e345e9cbf4b1dbf86b262bc") + ts.Require().Equal(common.Bytes2Hex(validators[1]), "35552c16704d214347f29fa77f77da6d75d7c752b742ad4855bae330426b823e742da31f816cc83bc16d69a9134be0cfb4a1d17ec34f1b5b32d5c20440b8536b1e88f0f2") + ts.Require().Equal(common.Bytes2Hex(validators[2]), "96c5d20b2a975c050e4220be276ace4892f4b41a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000") + ts.Require().Equal(common.Bytes2Hex(validators[3]), "980a75ecd1309ea12fa2ed87a8744fbfc9b863d589037a9ace3b590165ea1c0c5ac72bf600b7c88c1e435f41932c1132aae1bfa0bb68e46b96ccb12c3415e4d82af717d8") + ts.Require().Equal(common.Bytes2Hex(validators[4]), "a2959d3f95eae5dc7d70144ce1b73b403b7eb6e0b973c2d38487e58fd6e145491b110080fb14ac915a0411fc78f19e09a399ddee0d20c63a75d8f930f1694544ad2dc01b") + ts.Require().Equal(common.Bytes2Hex(validators[5]), "b71b214cb885500844365e95cd9942c7276e7fd8a2750ec6dded3dcdc2f351782310b0eadc077db59abca0f0cd26776e2e7acb9f3bce40b1fa5221fd1561226c6263cc5f") + ts.Require().Equal(common.Bytes2Hex(validators[6]), "f474cf03cceff28abc65c9cbae594f725c80e12d96c9b86c3400e529bfe184056e257c07940bb664636f689e8d2027c834681f8f878b73445261034e946bb2d901b4b878") } // see yui-ibc-solidity diff --git a/module/parlia.pb.go b/module/parlia.pb.go index 2c5d6d2..1ad7add 100644 --- a/module/parlia.pb.go +++ b/module/parlia.pb.go @@ -149,6 +149,7 @@ type ConsensusState struct { StateRoot []byte `protobuf:"bytes,1,opt,name=state_root,json=stateRoot,proto3" json:"state_root,omitempty"` Timestamp uint64 `protobuf:"varint,2,opt,name=timestamp,proto3" json:"timestamp,omitempty"` ValidatorsHash []byte `protobuf:"bytes,3,opt,name=validators_hash,json=validatorsHash,proto3" json:"validators_hash,omitempty"` + ValidatorSize uint64 `protobuf:"varint,4,opt,name=validator_size,json=validatorSize,proto3" json:"validator_size,omitempty"` } func (m *ConsensusState) Reset() { *m = ConsensusState{} } @@ -236,46 +237,47 @@ func init() { } var fileDescriptor_dc631224085c6c85 = []byte{ - // 612 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x53, 0xcd, 0x4e, 0xdb, 0x4c, - 0x14, 0x8d, 0x81, 0x2f, 0x24, 0x83, 0x81, 0x8f, 0x11, 0xaa, 0xdc, 0xb4, 0x75, 0xa3, 0xa0, 0x8a, - 0xa8, 0x15, 0x76, 0x93, 0xae, 0x51, 0x45, 0x51, 0xa5, 0xb0, 0x40, 0x42, 0xa6, 0xea, 0xa2, 0x1b, - 0x6b, 0x3c, 0x1e, 0xe2, 0x91, 0x6c, 0x4f, 0x34, 0x73, 0x6d, 0xa9, 0x7d, 0x82, 0x2e, 0xfb, 0x1a, - 0x7d, 0x13, 0x96, 0x2c, 0xbb, 0x6c, 0xe1, 0x45, 0xaa, 0xf9, 0x81, 0xb0, 0xe9, 0xdf, 0xee, 0xde, - 0x73, 0xcf, 0xb9, 0x33, 0xf7, 0xdc, 0x19, 0xb4, 0xcf, 0x33, 0x1a, 0x97, 0x7c, 0x5e, 0x00, 0x2d, - 0x39, 0xab, 0x41, 0xc5, 0x0b, 0x22, 0x4b, 0x4e, 0xe2, 0x76, 0xe2, 0xa2, 0x68, 0x21, 0x05, 0x08, - 0x3c, 0xe0, 0x19, 0x8d, 0xee, 0x13, 0x23, 0x57, 0x6e, 0x27, 0x83, 0xdd, 0xb9, 0x98, 0x0b, 0x43, - 0x8b, 0x75, 0x64, 0x15, 0x83, 0xa7, 0xba, 0x35, 0x15, 0x92, 0xc5, 0x56, 0xa1, 0x5b, 0xda, 0xc8, - 0x12, 0x46, 0x9f, 0x57, 0xd0, 0xc6, 0xb1, 0x01, 0xce, 0x81, 0x00, 0xc3, 0x0f, 0x51, 0x8f, 0x16, - 0x84, 0xd7, 0x29, 0xcf, 0x03, 0x6f, 0xe8, 0x8d, 0xd7, 0x92, 0x75, 0x93, 0x9f, 0xe4, 0xf8, 0x39, - 0xda, 0xe1, 0x19, 0x4d, 0x15, 0x08, 0xc9, 0x52, 0x92, 0xe7, 0x92, 0x29, 0x15, 0xac, 0x0c, 0xbd, - 0xb1, 0x9f, 0x6c, 0xf3, 0x8c, 0x9e, 0x6b, 0xfc, 0xc8, 0xc2, 0xf8, 0x25, 0xda, 0xd5, 0x5c, 0x2a, - 0xaa, 0x8a, 0x43, 0xa5, 0xaf, 0x9a, 0xaa, 0x52, 0x40, 0xb0, 0x6a, 0xe8, 0x98, 0x67, 0xf4, 0x78, - 0x59, 0x3a, 0x2f, 0x05, 0xe0, 0xd7, 0x68, 0xb3, 0x24, 0xc0, 0x14, 0xa4, 0x05, 0xd3, 0x13, 0x06, - 0x6b, 0x43, 0x6f, 0xbc, 0x31, 0x1d, 0x44, 0x7a, 0x66, 0x3d, 0x41, 0xe4, 0xee, 0xdd, 0x4e, 0xa2, - 0x99, 0x61, 0x24, 0xbe, 0x15, 0xd8, 0x0c, 0xef, 0xa3, 0x6d, 0x90, 0x8d, 0x02, 0x5e, 0xcf, 0xd3, - 0x05, 0x93, 0x5c, 0xe4, 0x41, 0xd7, 0x0c, 0xb0, 0x75, 0x0b, 0x9f, 0x19, 0x14, 0x3f, 0x40, 0xdd, - 0x0b, 0x29, 0x3e, 0xb1, 0x3a, 0x58, 0x1f, 0x7a, 0xe3, 0x5e, 0xe2, 0xb2, 0xd1, 0x1e, 0xea, 0xbf, - 0x7d, 0x37, 0x9b, 0x31, 0x92, 0x33, 0xa9, 0x49, 0x85, 0x89, 0x8c, 0x0b, 0x7e, 0xe2, 0xb2, 0xd1, - 0xe5, 0x0a, 0xea, 0x3a, 0xca, 0x21, 0xea, 0x02, 0x91, 0x73, 0x06, 0x86, 0xb2, 0x31, 0x7d, 0x16, - 0xfd, 0x7a, 0x3d, 0xd1, 0x5d, 0xe7, 0xc4, 0x89, 0xb4, 0x7c, 0x41, 0x24, 0xab, 0xc1, 0x78, 0xf8, - 0xf7, 0x72, 0x2b, 0xc2, 0x47, 0xc8, 0xce, 0xc5, 0xf2, 0x5b, 0xc3, 0x56, 0xff, 0x68, 0xd8, 0xa6, - 0x53, 0x38, 0xc7, 0xf6, 0xd0, 0x26, 0xa1, 0x54, 0x34, 0x35, 0xa4, 0x0b, 0x29, 0xc4, 0x85, 0xb1, - 0xdc, 0x4f, 0x7c, 0x07, 0x9e, 0x69, 0x0c, 0xbf, 0x40, 0x3b, 0xf6, 0xc4, 0xb4, 0x25, 0x25, 0xcf, - 0x09, 0x08, 0xa9, 0x82, 0xff, 0x86, 0xab, 0x63, 0x3f, 0xf9, 0xdf, 0x16, 0xde, 0xdf, 0xe1, 0x9a, - 0x6c, 0xa7, 0xbb, 0x4f, 0xee, 0x5a, 0xb2, 0x2d, 0x2c, 0xc9, 0xa3, 0x16, 0x6d, 0x1d, 0x8b, 0x5a, - 0xb1, 0x5a, 0x35, 0xca, 0x3e, 0xbe, 0x27, 0x08, 0x29, 0x1d, 0xa4, 0x52, 0x08, 0x70, 0xc6, 0xf7, - 0x0d, 0x92, 0x08, 0x01, 0xf8, 0x31, 0xea, 0x03, 0xaf, 0x98, 0x02, 0x52, 0x2d, 0x8c, 0x69, 0x6b, - 0xc9, 0x12, 0xd0, 0xfb, 0x5f, 0x1e, 0x9a, 0x16, 0x44, 0x15, 0xee, 0xb5, 0x6d, 0x2d, 0xe1, 0x19, - 0x51, 0xc5, 0xe8, 0xab, 0x87, 0xfc, 0x53, 0xae, 0x32, 0x56, 0x90, 0x96, 0x8b, 0x46, 0xe2, 0x47, - 0xa8, 0x6f, 0xad, 0xba, 0x7d, 0xf4, 0xfd, 0xa4, 0x67, 0x81, 0x93, 0x1c, 0x1f, 0xa2, 0x9e, 0x5d, - 0x7d, 0x3a, 0x71, 0x8b, 0x1a, 0xfd, 0x6e, 0x51, 0x6e, 0x4b, 0xeb, 0x56, 0x33, 0xb9, 0x27, 0x9f, - 0xba, 0x05, 0xfd, 0x83, 0x7c, 0xfa, 0xe6, 0xf4, 0xf2, 0x47, 0xd8, 0xb9, 0xbc, 0x0e, 0xbd, 0xab, - 0xeb, 0xd0, 0xfb, 0x7e, 0x1d, 0x7a, 0x5f, 0x6e, 0xc2, 0xce, 0xd5, 0x4d, 0xd8, 0xf9, 0x76, 0x13, - 0x76, 0x3e, 0xc4, 0x73, 0x0e, 0x45, 0x93, 0x45, 0x54, 0x54, 0x71, 0x4e, 0x80, 0x98, 0x9f, 0x5a, - 0x92, 0x2c, 0xe6, 0x19, 0x3d, 0xb0, 0x4d, 0x0f, 0x24, 0x2b, 0xc9, 0xc7, 0xb8, 0x12, 0x79, 0x53, - 0xb2, 0xac, 0x6b, 0x3e, 0xfd, 0xab, 0x9f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x8f, 0xdf, 0xf0, 0x7c, - 0x72, 0x04, 0x00, 0x00, + // 632 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x54, 0xcd, 0x6e, 0xd3, 0x40, + 0x10, 0x8e, 0xdb, 0x90, 0x26, 0x5b, 0xa7, 0xa5, 0xab, 0x0a, 0x99, 0x00, 0x26, 0x4a, 0x55, 0x35, + 0x02, 0xd5, 0x26, 0xe1, 0x5c, 0xa1, 0x52, 0x21, 0xa5, 0x87, 0x4a, 0x95, 0x83, 0x38, 0x70, 0x59, + 0xad, 0xd7, 0xdb, 0x78, 0x25, 0xdb, 0x1b, 0xed, 0x6e, 0x22, 0xd1, 0x27, 0xe0, 0xc8, 0x0b, 0xf0, + 0x00, 0xbc, 0x49, 0x8f, 0x3d, 0x72, 0x84, 0xf6, 0x45, 0xd0, 0xfe, 0xb4, 0xce, 0x85, 0xbf, 0xdb, + 0xcc, 0x37, 0xdf, 0x37, 0xf6, 0x7c, 0x33, 0x36, 0x38, 0x60, 0x29, 0x89, 0x0b, 0x36, 0xcb, 0x15, + 0x29, 0x18, 0xad, 0x94, 0x8c, 0xe7, 0x58, 0x14, 0x0c, 0xc7, 0xcb, 0x91, 0x8b, 0xa2, 0xb9, 0xe0, + 0x8a, 0xc3, 0x1e, 0x4b, 0x49, 0xb4, 0x4a, 0x8c, 0x5c, 0x79, 0x39, 0xea, 0xed, 0xce, 0xf8, 0x8c, + 0x1b, 0x5a, 0xac, 0x23, 0xab, 0xe8, 0x3d, 0xd7, 0xad, 0x09, 0x17, 0x34, 0xb6, 0x0a, 0xdd, 0xd2, + 0x46, 0x96, 0x30, 0xf8, 0xbc, 0x06, 0x36, 0x4f, 0x0c, 0x30, 0x55, 0x58, 0x51, 0xf8, 0x18, 0xb4, + 0x49, 0x8e, 0x59, 0x85, 0x58, 0x16, 0x78, 0x7d, 0x6f, 0xd8, 0x4c, 0x36, 0x4c, 0x7e, 0x9a, 0xc1, + 0x17, 0x60, 0x87, 0xa5, 0x04, 0x49, 0xc5, 0x05, 0x45, 0x38, 0xcb, 0x04, 0x95, 0x32, 0x58, 0xeb, + 0x7b, 0x43, 0x3f, 0xd9, 0x66, 0x29, 0x99, 0x6a, 0xfc, 0xd8, 0xc2, 0xf0, 0x15, 0xd8, 0xd5, 0x5c, + 0xc2, 0xcb, 0x92, 0xa9, 0x52, 0xbf, 0x2a, 0x92, 0x05, 0x57, 0xc1, 0xba, 0xa1, 0x43, 0x96, 0x92, + 0x93, 0xba, 0x34, 0x2d, 0xb8, 0x82, 0x6f, 0x40, 0xb7, 0xc0, 0x8a, 0x4a, 0x85, 0x72, 0xaa, 0x27, + 0x0c, 0x9a, 0x7d, 0x6f, 0xb8, 0x39, 0xee, 0x45, 0x7a, 0x66, 0x3d, 0x41, 0xe4, 0xde, 0x7b, 0x39, + 0x8a, 0x26, 0x86, 0x91, 0xf8, 0x56, 0x60, 0x33, 0x78, 0x00, 0xb6, 0x95, 0x58, 0x48, 0xc5, 0xaa, + 0x19, 0x9a, 0x53, 0xc1, 0x78, 0x16, 0xb4, 0xcc, 0x00, 0x5b, 0x77, 0xf0, 0xb9, 0x41, 0xe1, 0x23, + 0xd0, 0xba, 0x10, 0xfc, 0x92, 0x56, 0xc1, 0x46, 0xdf, 0x1b, 0xb6, 0x13, 0x97, 0x0d, 0xf6, 0x40, + 0xe7, 0xdd, 0xfb, 0xc9, 0x84, 0xe2, 0x8c, 0x0a, 0x4d, 0xca, 0x4d, 0x64, 0x5c, 0xf0, 0x13, 0x97, + 0x0d, 0xae, 0xd6, 0x40, 0xcb, 0x51, 0x8e, 0x40, 0x4b, 0x61, 0x31, 0xa3, 0xca, 0x50, 0x36, 0xc7, + 0xfb, 0xd1, 0xef, 0xd7, 0x13, 0xdd, 0x77, 0x4e, 0x9c, 0x48, 0xcb, 0xe7, 0x58, 0xd0, 0x4a, 0x19, + 0x0f, 0xff, 0x5d, 0x6e, 0x45, 0xf0, 0x18, 0xd8, 0xb9, 0x68, 0x76, 0x67, 0xd8, 0xfa, 0x5f, 0x0d, + 0xeb, 0x3a, 0x85, 0x73, 0x6c, 0x0f, 0x74, 0x31, 0x21, 0x7c, 0x51, 0x29, 0x34, 0x17, 0x9c, 0x5f, + 0x18, 0xcb, 0xfd, 0xc4, 0x77, 0xe0, 0xb9, 0xc6, 0xe0, 0x4b, 0xb0, 0x63, 0x9f, 0x88, 0x96, 0xb8, + 0x60, 0x19, 0x56, 0x5c, 0xc8, 0xe0, 0x41, 0x7f, 0x7d, 0xe8, 0x27, 0x0f, 0x6d, 0xe1, 0xc3, 0x3d, + 0xae, 0xc9, 0x76, 0xba, 0x55, 0x72, 0xcb, 0x92, 0x6d, 0xa1, 0x26, 0x0f, 0xbe, 0x7a, 0x60, 0xeb, + 0x84, 0x57, 0x92, 0x56, 0x72, 0x21, 0xed, 0xf5, 0x3d, 0x03, 0x40, 0xea, 0x00, 0x09, 0xce, 0x95, + 0x73, 0xbe, 0x63, 0x90, 0x84, 0x73, 0x05, 0x9f, 0x82, 0x8e, 0x62, 0x25, 0x95, 0x0a, 0x97, 0x73, + 0xe3, 0x5a, 0x33, 0xa9, 0x01, 0x7d, 0x00, 0xf5, 0x53, 0x51, 0x8e, 0x65, 0xee, 0xce, 0x6d, 0xab, + 0x86, 0x27, 0x58, 0xe6, 0x70, 0x1f, 0xd4, 0x08, 0x92, 0xec, 0x92, 0x9a, 0xc1, 0x9b, 0x49, 0xf7, + 0x1e, 0x9d, 0xb2, 0x4b, 0x3a, 0xf8, 0xe6, 0x01, 0xff, 0x8c, 0xc9, 0x94, 0xe6, 0x78, 0xc9, 0xf8, + 0x42, 0xc0, 0x27, 0xa0, 0x63, 0x2d, 0xbd, 0xfb, 0x38, 0x3a, 0x49, 0xdb, 0x02, 0xa7, 0x19, 0x3c, + 0x02, 0x6d, 0x7b, 0x22, 0x68, 0xe4, 0x16, 0x3a, 0xf8, 0xd3, 0x42, 0xdd, 0x36, 0x37, 0xac, 0x66, + 0xb4, 0x22, 0x1f, 0xbb, 0x45, 0xfe, 0x87, 0x7c, 0xfc, 0xf6, 0xec, 0xea, 0x67, 0xd8, 0xb8, 0xba, + 0x09, 0xbd, 0xeb, 0x9b, 0xd0, 0xfb, 0x71, 0x13, 0x7a, 0x5f, 0x6e, 0xc3, 0xc6, 0xf5, 0x6d, 0xd8, + 0xf8, 0x7e, 0x1b, 0x36, 0x3e, 0xc6, 0x33, 0xa6, 0xf2, 0x45, 0x1a, 0x11, 0x5e, 0xc6, 0x19, 0x56, + 0xd8, 0x7c, 0xd1, 0x05, 0x4e, 0x63, 0x96, 0x92, 0x43, 0xdb, 0xf4, 0x50, 0xd0, 0x02, 0x7f, 0x8a, + 0x4b, 0x9e, 0x2d, 0x0a, 0x9a, 0xb6, 0xcc, 0xcf, 0xe1, 0xf5, 0xaf, 0x00, 0x00, 0x00, 0xff, 0xff, + 0xa2, 0xbe, 0x36, 0x15, 0x9a, 0x04, 0x00, 0x00, } func (m *ClientState) Marshal() (dAtA []byte, err error) { @@ -481,6 +483,11 @@ func (m *ConsensusState) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.ValidatorSize != 0 { + i = encodeVarintParlia(dAtA, i, uint64(m.ValidatorSize)) + i-- + dAtA[i] = 0x20 + } if len(m.ValidatorsHash) > 0 { i -= len(m.ValidatorsHash) copy(dAtA[i:], m.ValidatorsHash) @@ -665,6 +672,9 @@ func (m *ConsensusState) Size() (n int) { if l > 0 { n += 1 + l + sovParlia(uint64(l)) } + if m.ValidatorSize != 0 { + n += 1 + sovParlia(uint64(m.ValidatorSize)) + } return n } @@ -1363,6 +1373,25 @@ func (m *ConsensusState) Unmarshal(dAtA []byte) error { m.ValidatorsHash = []byte{} } iNdEx = postIndex + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ValidatorSize", wireType) + } + m.ValidatorSize = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowParlia + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ValidatorSize |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipParlia(dAtA[iNdEx:]) diff --git a/module/prover.go b/module/prover.go index 88dd2de..e360a05 100644 --- a/module/prover.go +++ b/module/prover.go @@ -3,6 +3,7 @@ package module import ( "context" "fmt" + "github.com/ethereum/go-ethereum/common" "log" "time" @@ -79,16 +80,17 @@ func (pr *Prover) GetLatestFinalizedHeaderByLatestHeight(latestBlockNumber uint6 return nil, err } vote, err := getVoteAttestationFromHeader(header) - if vote != nil { - break + if err == nil && vote != nil { + return pr.queryVerifyingHeader(vote.Data.SourceNumber) } if pr.config.Debug { - if target%100 == 0 { - log.Printf("gettin finalized header : %d\n", target) + if target%constant.BlocksPerEpoch == 0 { + log.Printf("getting finalized header : %d\n", target) } } + target -= 1 } - return pr.queryVerifyingHeader(target) + return nil, fmt.Errorf("No finalized header found ") } // CreateMsgCreateClient creates a CreateClientMsg to this chain @@ -99,7 +101,7 @@ func (pr *Prover) CreateMsgCreateClient(_ string, dstHeader core.Header, _ sdk.A if err != nil { return nil, err } - previousValidators, err := extractValidatorSet(previousEpochHeader) + previousValidators, err := ExtractValidatorSet(previousEpochHeader) if err != nil { return nil, err } @@ -128,6 +130,7 @@ func (pr *Prover) CreateMsgCreateClient(_ string, dstHeader core.Header, _ sdk.A consensusState := ConsensusState{ Timestamp: previousEpochHeader.Time, ValidatorsHash: crypto.Keccak256(previousValidators...), + ValidatorSize: uint64(len(previousValidators)), // Since ibc handler may not be deployed at the target epoch when create_client is used, state_root is not obtained. StateRoot: pr.getStateRootOrEmpty(previousEpochHeader).Bytes(), } @@ -194,7 +197,16 @@ func (pr *Prover) SetupHeadersForUpdateByLatestHeight(clientStateLatestHeight ex h.(*Header).TrustedHeight = &trustedHeight if pr.config.Debug { - log.Printf("SetupHeadersForUpdate: targetHeight=%v, trustedHeight=%v \n", h.GetHeight(), trustedHeight) + targetValidatorsHash := common.Bytes2Hex(crypto.Keccak256(h.(*Header).TargetValidators...)) + parentValidatorsHash := common.Bytes2Hex(crypto.Keccak256(h.(*Header).ParentValidators...)) + target, _ := h.(*Header).DecodedTarget() + if target.Number.Uint64()%constant.BlocksPerEpoch == 0 { + newValidators, _ := ExtractValidatorSet(target) + newValidatorsHash := common.Bytes2Hex(crypto.Keccak256(newValidators...)) + log.Printf("SetupHeadersForUpdate: targetHeight=%v, trustedHeight=%v targetValidatorsHash=%s, parentValidatorsHash=%s, newValidatorsHash=%s\n", h.GetHeight(), trustedHeight, targetValidatorsHash, parentValidatorsHash, newValidatorsHash) + } else { + log.Printf("SetupHeadersForUpdate: targetHeight=%v, trustedHeight=%v targetValidatorsHash=%s, parentValidatorsHash=%s\n", h.GetHeight(), trustedHeight, targetValidatorsHash, parentValidatorsHash) + } } } return targetHeaders, nil @@ -261,9 +273,8 @@ func (pr *Prover) queryValidators(target uint64) ([][]byte, error) { return nil, fmt.Errorf("ValidatorSet was not found in current epoch : number= %d : %+v", currentEpoch, err) } return currentValidators, nil - } else { - return previousValidators, nil } + return previousValidators, nil } // queryETHHeaders returns the ETHHeaders @@ -290,7 +301,7 @@ func (pr *Prover) queryValidatorSet(epochBlockNumber uint64) ([][]byte, error) { if err != nil { return nil, err } - return extractValidatorSet(header) + return ExtractValidatorSet(header) } // newETHHeader returns the new ETHHeader diff --git a/module/prover_mainnet_test.go b/module/prover_mainnet_test.go deleted file mode 100644 index bef5a07..0000000 --- a/module/prover_mainnet_test.go +++ /dev/null @@ -1,91 +0,0 @@ -package module - -import ( - "log" - "testing" - - "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" - "github.com/datachainlab/ethereum-ibc-relay-chain/pkg/relay/ethereum" - "github.com/ethereum/go-ethereum/common" - "github.com/stretchr/testify/suite" -) - -type ProverMainnetTestSuite struct { - suite.Suite - prover *Prover -} - -func TestProverMainnetTestSuite(t *testing.T) { - suite.Run(t, new(ProverMainnetTestSuite)) -} - -func (ts *ProverMainnetTestSuite) SetupTest() { - chain, err := ethereum.NewChain(ethereum.ChainConfig{ - EthChainId: 56, - // We can get accountProof by eth_geProof only from AllThatNode - RpcAddr: "https://bsc-mainnet-rpc.allthatnode.com", - HdwMnemonic: hdwMnemonic, - HdwPath: hdwPath, - // TODO change address after starting mainnet test - IbcAddress: "0x151f3951FA218cac426edFe078fA9e5C6dceA500", - }) - ts.Require().NoError(err) - - config := ProverConfig{ - Debug: true, - } - ts.prover = NewProver(NewChain(chain), &config).(*Prover) -} - -func (ts *ProverMainnetTestSuite) TestQueryLatestFinalizedHeader() { - latestHeight, err := ts.prover.chain.LatestHeight() - ts.Require().NoError(err) - latest := latestHeight.GetRevisionHeight() - println(latest) - iHeader, err := ts.prover.GetLatestFinalizedHeaderByLatestHeight(latest) - ts.Require().NoError(err) - ts.Require().NoError(iHeader.ValidateBasic()) - - header := iHeader.(*Header) - - // target header - target, err := header.DecodedTarget() - ts.Require().NoError(err) - parent, err := header.DecodedParent() - ts.Require().NoError(err) - ts.Require().Equal(target.Number.Int64()-1, parent.Number.Int64()) - - // headers to verify - if target.Number.Uint64()%200 == 0 { - validators, err := extractValidatorSet(target) - ts.Require().NoError(err) - ts.Require().Len(validators, 21) - } - - // account proof - account, err := header.Account(ts.prover.chain.IBCAddress()) - ts.Require().NoError(err) - ts.Require().NotEqual(account.Root, common.Hash{}) - log.Println(account.Root) - - // setup - updating, err := ts.prover.SetupHeadersForUpdateByLatestHeight(types.NewHeight(header.GetHeight().GetRevisionNumber(), target.Number.Uint64()-1), header) - ts.Require().NoError(err) - ts.Require().Len(updating, 1) - ts.Require().Equal(updating[0].(*Header).GetHeight(), header.GetHeight()) - - // updating msg - pack, err := types.PackClientMessage(updating[0]) - ts.Require().NoError(err) - marshal, err := pack.Marshal() - ts.Require().NoError(err) - log.Println(common.Bytes2Hex(marshal)) - - for _, v := range header.TargetValidators { - log.Println(common.Bytes2Hex(v)) - } - log.Println("parent") - for _, v := range header.ParentValidators { - log.Println(common.Bytes2Hex(v)) - } -} diff --git a/module/prover_test.go b/module/prover_test.go index c02aaff..8424de4 100644 --- a/module/prover_test.go +++ b/module/prover_test.go @@ -69,16 +69,18 @@ func (r *mockChain) Header(_ context.Context, height uint64) (*types2.Header, er if header.Number.Int64() == 0 { header.Extra = append(header.Extra, make([]byte, extraVanity)...) for i := 1; i <= 4; i++ { + // Genesis validator doesn't have Vote address because the luban is after genesis header.Extra = append(header.Extra, common.Hex2Bytes(fmt.Sprintf("100000000000000000000000000000000000000%d", i))...) } header.Extra = append(header.Extra, make([]byte, extraSeal)...) } else { header.Extra = make([]byte, extraVanity) + header.Extra = append(header.Extra, 21) for i := 1; i <= 9; i++ { - header.Extra = append(header.Extra, common.Hex2Bytes(fmt.Sprintf("200000000000000000000000000000000000000%d", i))...) + header.Extra = append(header.Extra, common.Hex2Bytes(fmt.Sprintf("200000000000000000000000000000000000000%da4f05ea3dd58373394ba3a7ca3cabec78b69e044b2b09e82171d82e6e3998a9ed1f82226cd4540bcc8c3bafa8c9c725%d", i, i))...) } for i := 10; i <= 21; i++ { - header.Extra = append(header.Extra, common.Hex2Bytes(fmt.Sprintf("20000000000000000000000000000000000000%d", i))...) + header.Extra = append(header.Extra, common.Hex2Bytes(fmt.Sprintf("20000000000000000000000000000000000000%da4f05ea3dd58373394ba3a7ca3cabec78b69e044b2b09e82171d82e6e3998a9ed1f82226cd4540bcc8c3bafa8c9c72%d", i, i))...) } header.Extra = append(header.Extra, make([]byte, extraSeal)...) } @@ -196,13 +198,12 @@ func (ts *ProverTestSuite) TestCreateMsgCreateClient() { ts.Require().NoError(proto.Unmarshal(msg.ConsensusState.Value, &cs2)) target, err := previousEpochHeader.DecodedTarget() ts.Require().NoError(err) - validatorSet, err := extractValidatorSet(target) + validatorSet, err := ExtractValidatorSet(target) ts.Require().NoError(err) ts.Require().Equal(cs2.ValidatorsHash, crypto.Keccak256(validatorSet...)) ts.Require().Equal(cs2.Timestamp, target.Time) ts.Require().Equal(cs2.StateRoot, common.HexToHash("0xc3608871098f21b59607ef3fb9412a091de9246ad1281a92f5b07dc2f465b7a0").Bytes()) } - assertFn(400) assertFn(401) assertFn(599) } diff --git a/proto/ibc/lightclients/parlia/v1/parlia.proto b/proto/ibc/lightclients/parlia/v1/parlia.proto index c6cacaa..3774a80 100644 --- a/proto/ibc/lightclients/parlia/v1/parlia.proto +++ b/proto/ibc/lightclients/parlia/v1/parlia.proto @@ -36,6 +36,7 @@ message ConsensusState { bytes state_root = 1; uint64 timestamp = 2; bytes validators_hash = 3; + uint64 validator_size = 4; } message Misbehaviour { diff --git a/tool/testdata/README.md b/tool/testdata/README.md new file mode 100644 index 0000000..1310e26 --- /dev/null +++ b/tool/testdata/README.md @@ -0,0 +1,22 @@ +## Testdata making tool for lcp-parlia + +### Misbehavior +```sh +# src/client.rs test_success_submit_misbehavior +go run main.go misbehavior success + +# src/client.rs test_error_submit_misbehavior +go run main.go misbehavior error +``` + +### Header +```sh +# src/client.rs test_success_update_client_epoch +go run main.go header success epoch + +# src/client.rs test_success_update_client_non_epoch +go run main.go header success latest + +# src/client.rs test_error_update_client +go run main.go header error +``` \ No newline at end of file diff --git a/tool/testdata/internal/create_misbehavior.go b/tool/testdata/internal/create_misbehavior.go index 49a686b..e818bc7 100644 --- a/tool/testdata/internal/create_misbehavior.go +++ b/tool/testdata/internal/create_misbehavior.go @@ -2,18 +2,24 @@ package internal import ( "fmt" - "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" + "github.com/datachainlab/ethereum-ibc-relay-chain/pkg/relay/ethereum" "github.com/datachainlab/ibc-parlia-relay/module" + "github.com/datachainlab/ibc-parlia-relay/module/constant" "github.com/ethereum/go-ethereum/common" - "github.com/hyperledger-labs/yui-ibc-solidity/pkg/relay/ethereum" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/rlp" "github.com/spf13/cobra" "log" ) const ( - hdwMnemonic = "math razor capable expose worth grape metal sunset metal sudden usage scheme" - hdwPath = "m/44'/60'/0'/0/0" - IbcAddress = "0x702E40245797c5a2108A566b3CE2Bf14Bc6aF841" + hdwMnemonic = "math razor capable expose worth grape metal sunset metal sudden usage scheme" + hdwPath = "m/44'/60'/0'/0/0" + IbcAddress = "0x702E40245797c5a2108A566b3CE2Bf14Bc6aF841" + LocalNetValidatorSize = 3 + MainNetValidatorSize = 21 + MainNetIbcAddress = "0x151f3951FA218cac426edFe078fA9e5C6dceA500" ) func CreateMisbehavior() *cobra.Command { @@ -21,27 +27,22 @@ func CreateMisbehavior() *cobra.Command { Use: "misbehavior", Short: "Create testdata for misbehavior. ", } - cmd.AddCommand(localNet()) + cmd.AddCommand(misbehaviorSuccessCmd()) + cmd.AddCommand(misbehaviorErrorCmd()) return cmd } -// Launch local net before execute. -// - make chain -// -> Change NUMS_OF_VALIDATOR to 1 in docker-compose.yml -// -> Use e2e/chains/bsc/validators/keystore/bsc-validator1 for each chain's validator -// - make contracts -func localNet() *cobra.Command { +func misbehaviorSuccessCmd() *cobra.Command { return &cobra.Command{ - Use: "local", - Short: "create misbehavior testdata with local net", + Use: "success", + Short: "create misbehavior testdata for success", RunE: func(cmd *cobra.Command, args []string) error { chainID := int64(9999) - height := uint64(200) - header1, err := getHeader(chainID, 8645, height) + targetHeight, header1, err := getLocalHeader(chainID, 8645, 0) if err != nil { log.Panic(err) } - header2, err := getHeader(chainID, 8545, height) + _, header2, err := getLocalHeader(chainID, 8545, targetHeight) if err != nil { log.Panic(err) } @@ -53,15 +54,99 @@ func localNet() *cobra.Command { } // print hex for lcp-parlia test - pack, _ := types.PackMisbehaviour(&misbehavior) + pack, _ := types.PackClientMessage(&misbehavior) marshal, _ := pack.Marshal() - log.Println(common.Bytes2Hex(marshal)) + log.Println("misbehavior", common.Bytes2Hex(marshal)) + log.Println("trustedHeight", header1.TrustedHeight) + log.Println("targetValidatorHash", common.Bytes2Hex(crypto.Keccak256(header1.TargetValidators...))) + + epochCount := header1.GetHeight().GetRevisionHeight() / constant.BlocksPerEpoch + if header1.GetHeight().GetRevisionHeight()%constant.BlocksPerEpoch >= (LocalNetValidatorSize/2 + 1) { + log.Println("targetValidatorEpoch", epochCount*constant.BlocksPerEpoch) + } else { + log.Println("targetValidatorEpoch", (epochCount-1)*constant.BlocksPerEpoch) + } return nil }, } } -func getHeader(chainID int64, port int64, latestBlockNumber uint64) (*module.Header, error) { +func misbehaviorErrorCmd() *cobra.Command { + return &cobra.Command{ + Use: "error", + Short: "create misbehavior testdata for error", + RunE: func(cmd *cobra.Command, args []string) error { + chain, err := ethereum.NewChain(ethereum.ChainConfig{ + EthChainId: 56, + RpcAddr: "https://bsc-mainnet-rpc.allthatnode.com", + HdwMnemonic: hdwMnemonic, + HdwPath: hdwPath, + IbcAddress: MainNetIbcAddress, + }) + if err != nil { + return err + } + + config := module.ProverConfig{ + Debug: true, + } + prover := module.NewProver(module.NewChain(chain), &config).(*module.Prover) + + latestHeight, err := chain.LatestHeight() + if err != nil { + return err + } + latest := latestHeight.GetRevisionHeight() + println(latest) + header, err := prover.GetLatestFinalizedHeaderByLatestHeight(latest) + target, err := header.(*module.Header).DecodedTarget() + updating, err := prover.SetupHeadersForUpdateByLatestHeight(types.NewHeight(header.GetHeight().GetRevisionNumber(), target.Number.Uint64()-1), header.(*module.Header)) + if err != nil { + return err + } + + // Exactly same block + misbehavior := module.Misbehaviour{ + ClientId: "xx-parlia-1", + Header_1: updating[0].(*module.Header), + Header_2: updating[0].(*module.Header), + } + pack, _ := types.PackClientMessage(&misbehavior) + marshal, _ := pack.Marshal() + log.Println("Exactly same block: misbehavior", common.Bytes2Hex(marshal)) + log.Println("Exactly same block: height", target.Number.Int64()) + + // Invalid block + header2, _ := prover.GetLatestFinalizedHeaderByLatestHeight(latest) + updating2, _ := prover.SetupHeadersForUpdateByLatestHeight(types.NewHeight(header2.GetHeight().GetRevisionNumber(), target.Number.Uint64()-1), header2.(*module.Header)) + target2, _ := updating2[0].(*module.Header).DecodedTarget() + target2.Root = common.Hash{} + rlpTarget, err := rlp.EncodeToBytes(target2) + updating2[0].(*module.Header).Target = &module.ETHHeader{Header: rlpTarget} + misbehavior2 := module.Misbehaviour{ + ClientId: "xx-parlia-1", + Header_1: updating[0].(*module.Header), + Header_2: updating2[0].(*module.Header), + } + pack, _ = types.PackClientMessage(&misbehavior2) + marshal, _ = pack.Marshal() + log.Println("Invalid block: misbehavior", common.Bytes2Hex(marshal)) + log.Println("Invalid block: height", header.GetHeight()) + log.Println("Invalid block: target_validator_hash", common.Bytes2Hex(crypto.Keccak256(header.(*module.Header).TargetValidators...))) + log.Println("Invalid block: trusted_height", updating[0].(*module.Header).TrustedHeight) + epochCount := header.GetHeight().GetRevisionHeight() / constant.BlocksPerEpoch + if header.GetHeight().GetRevisionHeight()%constant.BlocksPerEpoch >= (MainNetValidatorSize/2 + 1) { + log.Println("Invalid block: targetValidatorEpoch", epochCount*constant.BlocksPerEpoch) + } else { + log.Println("Invalid block: targetValidatorEpoch", (epochCount-1)*constant.BlocksPerEpoch) + } + + return nil + }, + } +} + +func getLocalHeader(chainID int64, port int64, targetHeight uint64) (uint64, *module.Header, error) { chain, err := ethereum.NewChain(ethereum.ChainConfig{ EthChainId: chainID, RpcAddr: fmt.Sprintf("http://localhost:%d", port), @@ -70,31 +155,33 @@ func getHeader(chainID int64, port int64, latestBlockNumber uint64) (*module.Hea IbcAddress: IbcAddress, }) if err != nil { - return nil, err + return targetHeight, nil, err + } + if targetHeight == 0 { + latest, err := chain.LatestHeight() + if err != nil { + return targetHeight, nil, err + } + targetHeight = latest.GetRevisionHeight() } - config := module.ProverConfig{ Debug: true, } prover := module.NewProver(module.NewChain(chain), &config).(*module.Prover) // Get Finalized header - latestHeight := types.NewHeight(0, latestBlockNumber) + latestHeight := types.NewHeight(0, targetHeight) latest := latestHeight.GetRevisionHeight() iHeader, err := prover.GetLatestFinalizedHeaderByLatestHeight(latest) if err != nil { - return nil, err + return latest, nil, err } header := iHeader.(*module.Header) target, err := header.DecodedTarget() if err != nil { - return nil, err - } - - // Setup finalized header - updating, err := prover.SetupHeadersForUpdateByLatestHeight(types.NewHeight(header.GetHeight().GetRevisionNumber(), target.Number.Uint64()-1), header) - if err != nil { - return nil, err + return latest, nil, err } - return updating[0].(*module.Header), nil + trustedHeight := types.NewHeight(0, target.Number.Uint64()-5) + header.TrustedHeight = &trustedHeight + return latest, header, nil } diff --git a/tool/testdata/internal/create_update_client.go b/tool/testdata/internal/create_update_client.go new file mode 100644 index 0000000..bc0316b --- /dev/null +++ b/tool/testdata/internal/create_update_client.go @@ -0,0 +1,186 @@ +package internal + +import ( + "fmt" + "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" + "github.com/datachainlab/ethereum-ibc-relay-chain/pkg/relay/ethereum" + "github.com/datachainlab/ibc-parlia-relay/module" + "github.com/datachainlab/ibc-parlia-relay/module/constant" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/rlp" + "github.com/hyperledger-labs/yui-relayer/core" + "github.com/spf13/cobra" + "log" +) + +func CreateUpdateClient() *cobra.Command { + cmd := &cobra.Command{ + Use: "update", + Short: "Create testdata for update client. ", + } + cmd.AddCommand(updateClientSuccessCmd()) + cmd.AddCommand(updateClientErrorCmd()) + return cmd +} + +func updateClientSuccessCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "success", + Short: "create updateClient testdata for success", + } + cmd.AddCommand(&cobra.Command{ + Use: "latest", + Short: "for latest block", + RunE: func(cmd *cobra.Command, args []string) error { + prover, chain, err := createMainnetProver() + if err != nil { + return err + } + latest, err := chain.LatestHeight() + if err != nil { + return err + } + return printMainnetHeader(prover, latest.GetRevisionHeight()) + }, + }) + cmd.AddCommand(&cobra.Command{ + Use: "epoch", + Short: "for epoch block", + RunE: func(cmd *cobra.Command, args []string) error { + prover, chain, err := createMainnetProver() + if err != nil { + return err + } + latest, err := chain.LatestHeight() + if err != nil { + return err + } + epochCount := latest.GetRevisionHeight() / constant.BlocksPerEpoch + return printMainnetHeader(prover, epochCount*constant.BlocksPerEpoch+2) + }, + }) + return cmd +} + +func updateClientErrorCmd() *cobra.Command { + return &cobra.Command{ + Use: "error", + Short: "create updateClient testdata for error", + RunE: func(cmd *cobra.Command, args []string) error { + prover, chain, err := createMainnetProver() + if err != nil { + return err + } + latest, err := chain.LatestHeight() + if err != nil { + return err + } + header, err := prover.GetLatestFinalizedHeaderByLatestHeight(latest.GetRevisionHeight()) + if err != nil { + return err + } + target, err := header.(*module.Header).DecodedTarget() + if err != nil { + return err + } + updating, _ := prover.SetupHeadersForUpdateByLatestHeight(types.NewHeight(header.GetHeight().GetRevisionNumber(), target.Number.Uint64()-1), header.(*module.Header)) + target.Root = common.Hash{} + rlpTarget, err := rlp.EncodeToBytes(target) + updating[0].(*module.Header).Target = &module.ETHHeader{Header: rlpTarget} + pack, err := types.PackClientMessage(updating[0]) + if err != nil { + return err + } + marshal, err := pack.Marshal() + if err != nil { + return err + } + log.Println("header", common.Bytes2Hex(marshal)) + log.Println("height", header.GetHeight().GetRevisionHeight()) + log.Println("trustedHeight", header.(*module.Header).TrustedHeight.GetRevisionHeight()) + epochCount := header.GetHeight().GetRevisionHeight() / constant.BlocksPerEpoch + log.Println("currentEpochHeight", epochCount*constant.BlocksPerEpoch) + log.Println("targetValidatorHash", common.Bytes2Hex(crypto.Keccak256(header.(*module.Header).TargetValidators...))) + log.Println("targetValidatorSize", len(header.(*module.Header).TargetValidators)) + return nil + }, + } +} +func printMainnetHeader(prover *module.Prover, height uint64) error { + log.Println("printMainnetHeader latest=", height) + iHeader, err := prover.GetLatestFinalizedHeaderByLatestHeight(height) + if err != nil { + return err + } + if err = iHeader.ValidateBasic(); err != nil { + return err + } + header := iHeader.(*module.Header) + target, err := header.DecodedTarget() + if err != nil { + return err + } + + account, err := header.Account(common.HexToAddress(MainNetIbcAddress)) + if err != nil { + return err + } + + // setup + updating, err := prover.SetupHeadersForUpdateByLatestHeight(types.NewHeight(header.GetHeight().GetRevisionNumber(), target.Number.Uint64()-1), header) + if err != nil { + return err + } + + // updating msg + pack, err := types.PackClientMessage(updating[0]) + if err != nil { + return err + } + marshal, err := pack.Marshal() + if err != nil { + return err + } + log.Println("header", common.Bytes2Hex(marshal)) + log.Println("stateRoot", account.Root) + log.Println("height", header.GetHeight().GetRevisionHeight()) + log.Println("trustedHeight", header.TrustedHeight.GetRevisionHeight()) + epochCount := header.GetHeight().GetRevisionHeight() / constant.BlocksPerEpoch + log.Println("currentEpochHeight", epochCount*constant.BlocksPerEpoch) + + // validators hash + log.Println("targetValidatorSize", len(header.TargetValidators)) + log.Println("targetValidatorHash", common.Bytes2Hex(crypto.Keccak256(header.TargetValidators...))) + if target.Number.Uint64()%constant.BlocksPerEpoch == 0 { + newValidators, err := module.ExtractValidatorSet(target) + if err != nil { + return err + } + if len(newValidators) != MainNetValidatorSize { + return fmt.Errorf("invalid validator size for test") + } + log.Println("newValidatorHash", common.Bytes2Hex(crypto.Keccak256(newValidators...))) + log.Println("newValidatorSize", len(newValidators)) + } + return nil +} + +func createMainnetProver() (*module.Prover, core.Chain, error) { + chain, err := ethereum.NewChain(ethereum.ChainConfig{ + EthChainId: 56, + RpcAddr: "https://bsc-mainnet-rpc.allthatnode.com", + HdwMnemonic: hdwMnemonic, + HdwPath: hdwPath, + IbcAddress: MainNetIbcAddress, + }) + if err != nil { + return nil, chain, err + } + + config := module.ProverConfig{ + Debug: true, + } + ec := module.NewChain(chain) + return module.NewProver(ec, &config).(*module.Prover), chain, nil +} diff --git a/tool/testdata/main.go b/tool/testdata/main.go index 10cb96e..a062ee8 100644 --- a/tool/testdata/main.go +++ b/tool/testdata/main.go @@ -12,6 +12,7 @@ func main() { var rootCmd = &cobra.Command{} rootCmd.AddCommand(internal.CreateMisbehavior()) + rootCmd.AddCommand(internal.CreateUpdateClient()) if err := rootCmd.ExecuteContext(context.Background()); err != nil { log.Panicf("Failed to run command : %+v", err)