diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 61fb116..49d129c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -4,13 +4,20 @@ on: push: branches: - main + - develop pull_request: + types: + - opened + - reopened + - synchronize + - ready_for_review jobs: unit-test: name: unit-test timeout-minutes: 10 runs-on: ubuntu-latest + if: github.event.pull_request.draft == false steps: - name: checkout uses: actions/checkout@v4 @@ -27,11 +34,12 @@ jobs: # still using the deprecated types in ibc-go v8 args: --timeout=5m0s --disable staticcheck - name: test - run: go test -v ./... + run: go test -v ./module e2e: name: e2e timeout-minutes: 45 runs-on: ubuntu-latest + if: github.event.pull_request.draft == false steps: - name: checkout uses: actions/checkout@v4 @@ -46,5 +54,8 @@ jobs: run: | make chain make contracts + sleep 20 make relayer make test + - name: integration-test + run: go test -v ./tests -tags dev -ldflags="-X github.com/datachainlab/ibc-parlia-relay/module/constant.blocksPerEpoch=20" diff --git a/e2e/chains/bsc/Dockerfile.bootstrap b/e2e/chains/bsc/Dockerfile.bootstrap index 8299439..b7da3b7 100644 --- a/e2e/chains/bsc/Dockerfile.bootstrap +++ b/e2e/chains/bsc/Dockerfile.bootstrap @@ -3,7 +3,7 @@ FROM ghcr.io/foundry-rs/foundry:nightly-462b2ac6c038dc24b8f38b0c59b664d0740604c2 RUN apk add --d --no-cache ca-certificates npm nodejs bash alpine-sdk expect jq curl bash python3 RUN curl -sSL https://install.python-poetry.org | python3 - -RUN git clone https://github.com/binance-chain/bsc-genesis-contract.git -b v1.2.2 /root/genesis \ +RUN git clone https://github.com/bnb-chain/bsc-genesis-contract -b v1.2.4 /root/genesis \ && cd /root/genesis && npm ci RUN cd /root/genesis && /root/.local/bin/poetry install diff --git a/e2e/chains/bsc/Makefile b/e2e/chains/bsc/Makefile index 1fb9a70..a3085f6 100644 --- a/e2e/chains/bsc/Makefile +++ b/e2e/chains/bsc/Makefile @@ -10,7 +10,7 @@ bootstrap: .PHONY:network network: - 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-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 .PHONY:network-down diff --git a/e2e/chains/bsc/docker-compose.bsc.yml b/e2e/chains/bsc/docker-compose.bsc.yml index 075f3e5..a1adf4d 100644 --- a/e2e/chains/bsc/docker-compose.bsc.yml +++ b/e2e/chains/bsc/docker-compose.bsc.yml @@ -4,6 +4,6 @@ services: context: . dockerfile: Dockerfile.bsc args: - GIT_SOURCE: https://github.com/binance-chain/bsc.git - GIT_CHECKOUT_BRANCH: v1.4.8 + GIT_SOURCE: https://github.com/bnb-chain/bsc + GIT_CHECKOUT_BRANCH: v1.4.13 image: bsc-geth:docker-local diff --git a/e2e/chains/bsc/docker-compose.simple.yml b/e2e/chains/bsc/docker-compose.simple.yml index ff20a4c..3efc0a5 100644 --- a/e2e/chains/bsc/docker-compose.simple.yml +++ b/e2e/chains/bsc/docker-compose.simple.yml @@ -21,8 +21,8 @@ services: environment: BLOCKS_PER_EPOCH: 20 INIT_HOLDER_BALANCE: "500000000000000000000" - NUMS_OF_VALIDATOR: 3 - INIT_NUM_OF_CABINETS: 2 + NUMS_OF_VALIDATOR: 5 + INIT_NUM_OF_CABINETS: 4 volumes: - bsc-rpc:/root/storage/bsc-rpc - bsc-validator1-1:/root/storage/bsc-validator1 diff --git a/e2e/chains/bsc/genesis/contracts/BSCValidatorSet.sol b/e2e/chains/bsc/genesis/contracts/BSCValidatorSet.sol index 5b499bd..2db490e 100644 --- a/e2e/chains/bsc/genesis/contracts/BSCValidatorSet.sol +++ b/e2e/chains/bsc/genesis/contracts/BSCValidatorSet.sol @@ -22,13 +22,12 @@ interface ICrossChain { } 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; + uint256 public constant DUSTY_INCOMING = 1e17; uint8 public constant JAIL_MESSAGE_TYPE = 1; uint8 public constant VALIDATORS_UPDATE_MESSAGE_TYPE = 0; @@ -38,7 +37,8 @@ contract BSCValidatorSet is IBSCValidatorSet, System, IParamSubscriber, IApplica uint256 public constant EXPIRE_TIME_SECOND_GAP = 1000; uint256 public constant MAX_NUM_OF_VALIDATORS = 100; - bytes public constant INIT_VALIDATORSET_BYTES = hex"f905ec80f905e8f846942a7cdd959bfe8d9487b2a43b33565295a698f7e294b6a7edd747c0554875d3fc531d19ba1497992c5e941ff80f3f7f110ffd8920a3ac38fdef318fe94a3f86048c27395000f846946488aa4d1955ee33403f8ccb1d4de5fb97c7ade294220f003d8bdfaadf52aa1e55ae4cc485e6794875941a87e90e440a39c99aa9cb5cea0ad6a3f0b2407b86048c27395000f846949ef9f4360c606c7ab4db26b016007d3ad0ab86a0946103af86a874b705854033438383c82575f25bc29418e2db06cbff3e3c5f856410a1838649e760175786048c27395000f84694ee01c3b1283aa067c58eab4709f85e99d46de5fe94ee4b9bfb1871c64e2bcabb1dc382dc8b7c4218a29415904ab26ab0e99d70b51c220ccdcccabee6e29786048c27395000f84694685b1ded8013785d6623cc18d214320b6bb6475994a20ef4e5e4e7e36258dbf51f4d905114cb1b34bc9413e39085dc88704f4394d35209a02b1a9520320c86048c27395000f8469478f3adfc719c99674c072166708589033e2d9afe9448a30d5eaa7b64492a160f139e2da2800ec3834e94055838358c29edf4dcc1ba1985ad58aedbb6be2b86048c27395000f84694c2be4ec20253b8642161bc3f444f53679c1f3d479466f50c616d737e60d7ca6311ff0d9c434197898a94d1d678a2506eeaa365056fe565df8bc8659f28b086048c27395000f846942f7be8361c80a4c1e7e9aaf001d0877f1cfde218945f93992ac37f3e61db2ef8a587a436a161fd210b94ecbc4fb1a97861344dad0867ca3cba2b860411f086048c27395000f84694ce2fd7544e0b2cc94692d4a704debef7bcb613289444abc67b4b2fba283c582387f54c9cba7c34bafa948acc2ab395ded08bb75ce85bf0f95ad2abc51ad586048c27395000f84694b8f7166496996a7da21cf1f1b04d9b3e26a3d077946770572763289aac606e4f327c2f6cc1aa3b3e3b94882d745ed97d4422ca8da1c22ec49d880c4c097286048c27395000f846942d4c407bbe49438ed859fe965b140dcf1aab71a9943ad0939e120f33518fbba04631afe7a3ed6327b194b2bbb170ca4e499a2b0f3cc85ebfa6e8c4dfcbea86048c27395000f846946bbad7cf34b5fa511d8e963dbba288b1960e75d694853b0f6c324d1f4e76c8266942337ac1b0af1a229442498946a51ca5924552ead6fc2af08b94fcba648601d1a94a2000f846944430b3230294d12c6ab2aac5c2cd68e80b16b581947b107f4976a252a6939b771202c28e64e03f52d694795811a7f214084116949fc4f53cedbf189eeab28601d1a94a2000f84694ea0a6e3c511bbd10f4519ece37dc24887e11b55d946811ca77acfb221a49393c193f3a22db829fcc8e9464feb7c04830dd9ace164fc5c52b3f5a29e5018a8601d1a94a2000f846947ae2f5b9e386cd1b50a4550696d957cb4900f03a94e83bcc5077e6b873995c24bac871b5ad856047e19464e48d4057a90b233e026c1041e6012ada897fe88601d1a94a2000f8469482012708dafc9e1b880fd083b32182b869be8e09948e5adc73a2d233a1b496ed3115464dd6c7b887509428b383d324bc9a37f4e276190796ba5a8947f5ed8601d1a94a2000f8469422b81f8e175ffde54d797fe11eb03f9e3bf75f1d94a1c3ef7ca38d8ba80cce3bfc53ebd2903ed21658942767f7447f7b9b70313d4147b795414aecea54718601d1a94a2000f8469468bf0b8b6fb4e317a0f9d6f03eaf8ce6675bc60d94675cfe570b7902623f47e7f59c9664b5f5065dcf94d84f0d2e50bcf00f2fc476e1c57f5ca2d57f625b8601d1a94a2000f846948c4d90829ce8f72d0163c1d5cf348a862d5506309485c42a7b34309bee2ed6a235f86d16f059deec5894cc2cedc53f0fa6d376336efb67e43d167169f3b78601d1a94a2000f8469435e7a025f4da968de7e4d7e4004197917f4070f194b1182abaeeb3b4d8eba7e6a4162eac7ace23d57394c4fd0d870da52e73de2dd8ded19fe3d26f43a1138601d1a94a2000f84694d6caa02bbebaebb5d7e581e4b66559e635f805ff94c07335cf083c1c46a487f0325769d88e163b653694efaff03b42e41f953a925fc43720e45fb61a19938601d1a94a2000"; + bytes public constant INIT_VALIDATORSET_BYTES = + hex"f905ec80f905e8f846942a7cdd959bfe8d9487b2a43b33565295a698f7e294b6a7edd747c0554875d3fc531d19ba1497992c5e941ff80f3f7f110ffd8920a3ac38fdef318fe94a3f86048c27395000f846946488aa4d1955ee33403f8ccb1d4de5fb97c7ade294220f003d8bdfaadf52aa1e55ae4cc485e6794875941a87e90e440a39c99aa9cb5cea0ad6a3f0b2407b86048c27395000f846949ef9f4360c606c7ab4db26b016007d3ad0ab86a0946103af86a874b705854033438383c82575f25bc29418e2db06cbff3e3c5f856410a1838649e760175786048c27395000f84694ee01c3b1283aa067c58eab4709f85e99d46de5fe94ee4b9bfb1871c64e2bcabb1dc382dc8b7c4218a29415904ab26ab0e99d70b51c220ccdcccabee6e29786048c27395000f84694685b1ded8013785d6623cc18d214320b6bb6475994a20ef4e5e4e7e36258dbf51f4d905114cb1b34bc9413e39085dc88704f4394d35209a02b1a9520320c86048c27395000f8469478f3adfc719c99674c072166708589033e2d9afe9448a30d5eaa7b64492a160f139e2da2800ec3834e94055838358c29edf4dcc1ba1985ad58aedbb6be2b86048c27395000f84694c2be4ec20253b8642161bc3f444f53679c1f3d479466f50c616d737e60d7ca6311ff0d9c434197898a94d1d678a2506eeaa365056fe565df8bc8659f28b086048c27395000f846942f7be8361c80a4c1e7e9aaf001d0877f1cfde218945f93992ac37f3e61db2ef8a587a436a161fd210b94ecbc4fb1a97861344dad0867ca3cba2b860411f086048c27395000f84694ce2fd7544e0b2cc94692d4a704debef7bcb613289444abc67b4b2fba283c582387f54c9cba7c34bafa948acc2ab395ded08bb75ce85bf0f95ad2abc51ad586048c27395000f84694b8f7166496996a7da21cf1f1b04d9b3e26a3d077946770572763289aac606e4f327c2f6cc1aa3b3e3b94882d745ed97d4422ca8da1c22ec49d880c4c097286048c27395000f846942d4c407bbe49438ed859fe965b140dcf1aab71a9943ad0939e120f33518fbba04631afe7a3ed6327b194b2bbb170ca4e499a2b0f3cc85ebfa6e8c4dfcbea86048c27395000f846946bbad7cf34b5fa511d8e963dbba288b1960e75d694853b0f6c324d1f4e76c8266942337ac1b0af1a229442498946a51ca5924552ead6fc2af08b94fcba648601d1a94a2000f846944430b3230294d12c6ab2aac5c2cd68e80b16b581947b107f4976a252a6939b771202c28e64e03f52d694795811a7f214084116949fc4f53cedbf189eeab28601d1a94a2000f84694ea0a6e3c511bbd10f4519ece37dc24887e11b55d946811ca77acfb221a49393c193f3a22db829fcc8e9464feb7c04830dd9ace164fc5c52b3f5a29e5018a8601d1a94a2000f846947ae2f5b9e386cd1b50a4550696d957cb4900f03a94e83bcc5077e6b873995c24bac871b5ad856047e19464e48d4057a90b233e026c1041e6012ada897fe88601d1a94a2000f8469482012708dafc9e1b880fd083b32182b869be8e09948e5adc73a2d233a1b496ed3115464dd6c7b887509428b383d324bc9a37f4e276190796ba5a8947f5ed8601d1a94a2000f8469422b81f8e175ffde54d797fe11eb03f9e3bf75f1d94a1c3ef7ca38d8ba80cce3bfc53ebd2903ed21658942767f7447f7b9b70313d4147b795414aecea54718601d1a94a2000f8469468bf0b8b6fb4e317a0f9d6f03eaf8ce6675bc60d94675cfe570b7902623f47e7f59c9664b5f5065dcf94d84f0d2e50bcf00f2fc476e1c57f5ca2d57f625b8601d1a94a2000f846948c4d90829ce8f72d0163c1d5cf348a862d5506309485c42a7b34309bee2ed6a235f86d16f059deec5894cc2cedc53f0fa6d376336efb67e43d167169f3b78601d1a94a2000f8469435e7a025f4da968de7e4d7e4004197917f4070f194b1182abaeeb3b4d8eba7e6a4162eac7ace23d57394c4fd0d870da52e73de2dd8ded19fe3d26f43a1138601d1a94a2000f84694d6caa02bbebaebb5d7e581e4b66559e635f805ff94c07335cf083c1c46a487f0325769d88e163b653694efaff03b42e41f953a925fc43720e45fb61a19938601d1a94a2000"; uint32 public constant ERROR_UNKNOWN_PACKAGE_TYPE = 101; uint32 public constant ERROR_FAIL_CHECK_VALIDATORS = 102; @@ -48,14 +48,14 @@ contract BSCValidatorSet is IBSCValidatorSet, System, IParamSubscriber, IApplica uint256 public constant INIT_NUM_OF_CABINETS = 21; uint256 public constant EPOCH = 200; - /*********************** state of the contract **************************/ + /*----------------- 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; + mapping(address => uint256) public currentValidatorSetMap; uint256 public numOfJailed; uint256 public constant BLOCK_FEES_RATIO_SCALE = 10000; @@ -84,7 +84,7 @@ contract BSCValidatorSet is IBSCValidatorSet, System, IParamSubscriber, IApplica uint256 public constant INIT_SYSTEM_REWARD_RATIO = 625; // 625/10000 is 1/16 uint256 public constant MAX_SYSTEM_REWARD_BALANCE = 100 ether; - uint256 public systemRewardRatio; + uint256 public systemRewardBaseRatio; uint256 public previousHeight; uint256 public previousBalanceOfSystemReward; // deprecated bytes[] public previousVoteAddrFullSet; @@ -95,12 +95,15 @@ contract BSCValidatorSet is IBSCValidatorSet, System, IParamSubscriber, IApplica Validator[] private _tmpMigratedValidatorSet; bytes[] private _tmpMigratedVoteAddrs; + // BEP-341 Validators can produce consecutive blocks + uint256 public turnLength; // Consecutive number of blocks a validator receives priority for block production + uint256 public systemRewardAntiMEVRatio; + struct Validator { address consensusAddress; address payable feeAddress; address BBCFeeAddress; - uint64 votingPower; - + uint64 votingPower; // only in state bool jailed; uint256 incoming; @@ -108,24 +111,22 @@ contract BSCValidatorSet is IBSCValidatorSet, System, IParamSubscriber, IApplica struct ValidatorExtra { // BEP-127 Temporary Maintenance - uint256 enterMaintenanceHeight; // the height from where the validator enters 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 **************************/ + /*----------------- cross chain package -----------------*/ struct IbcValidatorSetPackage { - uint8 packageType; + uint8 packageType; Validator[] validatorSet; bytes[] voteAddrs; } - /*********************** modifiers **************************/ + /*----------------- modifiers -----------------*/ modifier noEmptyDeposit() { require(msg.value > 0, "deposit value is zero"); _; @@ -136,7 +137,7 @@ contract BSCValidatorSet is IBSCValidatorSet, System, IParamSubscriber, IApplica ValidatorExtra memory validatorExtra; // init validatorExtraSet uint256 validatorsNum = currentValidatorSet.length; - for (uint i; i newLength) { @@ -286,19 +295,20 @@ contract BSCValidatorSet is IBSCValidatorSet, System, IParamSubscriber, IApplica // - 1. validators exit maintenance // - 2. clear all maintainInfo // - 3. get unjailed validators from validatorSet - (Validator[] memory validatorSetTemp, bytes[] memory voteAddrsTemp) = _forceMaintainingValidatorsExit(_validatorSet, _voteAddrs); + (Validator[] memory validatorSetTemp, bytes[] memory voteAddrsTemp) = + _forceMaintainingValidatorsExit(_validatorSet, _voteAddrs); // step 1: distribute incoming - for (uint i; i < currentValidatorSet.length; ++i) { + for (uint256 i; i < currentValidatorSet.length; ++i) { uint256 incoming = currentValidatorSet[i].incoming; if (incoming != 0) { currentValidatorSet[i].incoming = 0; - IStakeHub(STAKE_HUB_ADDR).distributeReward{value : incoming}(currentValidatorSet[i].consensusAddress); + IStakeHub(STAKE_HUB_ADDR).distributeReward{ value: incoming }(currentValidatorSet[i].consensusAddress); } } // step 2: do dusk transfer - if (address(this).balance>0) { + if (address(this).balance > 0) { emit systemTransfer(address(this).balance); address(uint160(SYSTEM_REWARD_ADDR)).transfer(address(this).balance); } @@ -317,19 +327,24 @@ contract BSCValidatorSet is IBSCValidatorSet, System, IParamSubscriber, IApplica /** * @dev Collect all fee of transactions from the current block and deposit it to the contract - * - * @param valAddr The validator address who produced the current block - */ + * + * @param valAddr The validator address who produced the current block + */ function deposit(address valAddr) external payable onlyCoinbase onlyInit noEmptyDeposit onlyZeroGasPrice { uint256 value = msg.value; uint256 index = currentValidatorSetMap[valAddr]; - if (isSystemRewardIncluded == false){ - systemRewardRatio = INIT_SYSTEM_REWARD_RATIO; + if (isSystemRewardIncluded == false) { + systemRewardBaseRatio = INIT_SYSTEM_REWARD_RATIO; burnRatio = INIT_BURN_RATIO; isSystemRewardIncluded = true; } + uint256 systemRewardRatio = systemRewardBaseRatio; + if (turnLength > 1 && systemRewardAntiMEVRatio > 0) { + systemRewardRatio += systemRewardAntiMEVRatio * (block.number % turnLength) / (turnLength - 1); + } + if (value > 0 && systemRewardRatio > 0) { uint256 toSystemReward = msg.value.mul(systemRewardRatio).div(BLOCK_FEES_RATIO_SCALE); if (toSystemReward > 0) { @@ -350,231 +365,100 @@ contract BSCValidatorSet is IBSCValidatorSet, System, IParamSubscriber, IApplica } } - if (index>0) { - Validator storage validator = currentValidatorSet[index-1]; + if (index > 0) { + Validator storage validator = currentValidatorSet[index - 1]; if (validator.jailed) { - emit deprecatedDeposit(valAddr,value); + emit deprecatedDeposit(valAddr, value); } else { totalInComing = totalInComing.add(value); validator.incoming = validator.incoming.add(value); - emit validatorDeposit(valAddr,value); + emit validatorDeposit(valAddr, value); } } else { // get incoming from deprecated validator; - emit deprecatedDeposit(valAddr,value); + emit deprecatedDeposit(valAddr, value); } } - 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 < validatorsNum; ++i) { - if (isMigrated[i] == 1) { - if (currentValidatorSet[i].incoming != 0) { - directAddrs[directSize] = payable(currentValidatorSet[i].consensusAddress); - directAmounts[directSize] = currentValidatorSet[i].incoming; - isMigrated[directSize] = 1; // directSize must be less than i. so we can use directSize as index - ++directSize; - } - } else if (currentValidatorSet[i].incoming >= 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; - isMigrated[directSize] = 0; - ++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; i 0) { - for (uint i; i < directAddrs.length; ++i) { - if (isMigrated[i] == 1) { - IStakeHub(STAKE_HUB_ADDR).distributeReward{value : directAmounts[i]}(directAddrs[i]); - } else { - bool success = directAddrs[i].send(directAmounts[i]); - if (success) { - emit directTransfer(directAddrs[i], directAmounts[i]); - } else { - emit directTransferFail(directAddrs[i], directAmounts[i]); - } - } - } - } + function distributeFinalityReward( + address[] calldata valAddrs, + uint256[] calldata weights + ) external onlyCoinbase oncePerBlock onlyZeroGasPrice onlyInit { + uint256 totalValue; + uint256 balanceOfSystemReward = address(SYSTEM_REWARD_ADDR).balance; + if (balanceOfSystemReward > MAX_SYSTEM_REWARD_BALANCE) { + // when a slash happens, theres will no rewards in some epochs, + // it's tolerated because slash happens rarely + totalValue = balanceOfSystemReward.sub(MAX_SYSTEM_REWARD_BALANCE); + } else { + return; } - for (uint i; i < currentValidatorSet.length; ++i) { - if (currentValidatorSet[i].incoming != 0) { - currentValidatorSet[i].incoming = 0; - } + totalValue = ISystemReward(SYSTEM_REWARD_ADDR).claimRewards(payable(address(this)), totalValue); + if (totalValue == 0) { + return; } - // step 4: do dusk transfer - if (address(this).balance>0) { - emit systemTransfer(address(this).balance); - address(uint160(SYSTEM_REWARD_ADDR)).transfer(address(this).balance); + uint256 totalWeight; + for (uint256 i; i < weights.length; ++i) { + totalWeight += weights[i]; } - - // step 5: do update validator set state - totalInComing = 0; - numOfJailed = 0; - if (validatorSetTemp.length > 0) { - doUpdateState(validatorSetTemp, voteAddrsTemp); + if (totalWeight == 0) { + return; } - // step 6: clean slash contract - ISlashIndicator(SLASH_CONTRACT_ADDR).clean(); - emit validatorSetUpdated(); - return CODE_OK; - } + uint256 value; + address valAddr; + uint256 index; - /** - * @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) { + 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); } } } + /*----------------- View Functions -----------------*/ /** * @notice Return the vote address and consensus address of the validators in `currentValidatorSet` that are not jailed - */ + */ function getLivingValidators() external view override returns (address[] memory, bytes[] memory) { - uint n = currentValidatorSet.length; - uint living; - for (uint i; i 0 ? numOfCabinets : INIT_NUM_OF_CABINETS; @@ -596,49 +480,39 @@ contract BSCValidatorSet is IBSCValidatorSet, System, IParamSubscriber, IApplica if (validators.length <= _numOfCabinets) { return (validators, voteAddrs); } - - if ((validators.length - _numOfCabinets) < _maxNumOfWorkingCandidates){ - _maxNumOfWorkingCandidates = validators.length - _numOfCabinets; - } - if (_maxNumOfWorkingCandidates > 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); - } - +// remove unused shuffle address[] memory miningValidators = new address[](_numOfCabinets); bytes[] memory miningVoteAddrs = new bytes[](_numOfCabinets); // modify to rotate validators start uint256 epochNumber = block.number / EPOCH; uint256 start = epochNumber % validators.length; uint256 target = start; - for (uint i; i<_numOfCabinets; ++i) { - target += i; + for (uint i; i<_numOfCabinets; i++) { + target += 1; if (target >= validators.length){ target = 0; } -// modify end miningValidators[i] = validators[target]; miningVoteAddrs[i] = voteAddrs[target]; +// modify end } return (miningValidators, miningVoteAddrs); } /** * @notice Return the consensus address of the validators in `currentValidatorSet` that are not jailed and not maintaining - */ - function getValidators() public view returns(address[] memory) { - uint n = currentValidatorSet.length; - uint valid = 0; - for (uint i; i= currentValidatorSet.length) { return false; } @@ -665,21 +550,10 @@ contract BSCValidatorSet is IBSCValidatorSet, System, IParamSubscriber, IApplica return !currentValidatorSet[index].jailed && !validatorExtraSet[index].isMaintaining; } - /** - * @notice Return the current incoming of the validator - */ - function getIncoming(address validator)external view returns(uint256) { - uint256 index = currentValidatorSetMap[validator]; - if (index<=0) { - return 0; - } - return currentValidatorSet[index-1].incoming; - } - /** * @notice Return whether the validator is a working validator(not jailed or maintaining) by consensus address - * Will return false if the validator is not in `currentValidatorSet` - */ + * Will return false if the validator is not in `currentValidatorSet` + */ function isCurrentValidator(address validator) external view override returns (bool) { uint256 index = currentValidatorSetMap[validator]; if (index <= 0) { @@ -691,56 +565,22 @@ contract BSCValidatorSet is IBSCValidatorSet, System, IParamSubscriber, IApplica return isWorkingValidator(index); } - function distributeFinalityReward(address[] calldata valAddrs, uint256[] calldata weights) external onlyCoinbase oncePerBlock onlyZeroGasPrice onlyInit { - uint256 totalValue; - uint256 balanceOfSystemReward = address(SYSTEM_REWARD_ADDR).balance; - if (balanceOfSystemReward > MAX_SYSTEM_REWARD_BALANCE) { - // when a slash happens, theres will no rewards in some epochs, - // it's tolerated because slash happens rarely - totalValue = balanceOfSystemReward.sub(MAX_SYSTEM_REWARD_BALANCE); - } else { - return; - } - - totalValue = ISystemReward(SYSTEM_REWARD_ADDR).claimRewards(payable(address(this)), totalValue); - 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); - } - } + /** + * @notice Return the index of the validator in `currentValidatorSet`(from 0 to `currentValidatorSet.length-1`) + */ + 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 getWorkingValidatorCount() public view returns(uint256 workingValidatorCount) { + /** + * @notice Return the number of mining validators. + * The function name is misleading, it should be `getMiningValidatorCount`. But it's kept for compatibility. + */ + function getWorkingValidatorCount() public view returns (uint256 workingValidatorCount) { workingValidatorCount = getValidators().length; uint256 _numOfCabinets = numOfCabinets > 0 ? numOfCabinets : INIT_NUM_OF_CABINETS; if (workingValidatorCount > _numOfCabinets) { @@ -751,15 +591,15 @@ contract BSCValidatorSet is IBSCValidatorSet, System, IParamSubscriber, IApplica } } - /*********************** For slash **************************/ - function misdemeanor(address validator) external onlySlash initValidatorExtraSet override { + /*----------------- For slash -----------------*/ + function misdemeanor(address validator) external override onlySlash initValidatorExtraSet { uint256 validatorIndex = _misdemeanor(validator); if (canEnterMaintenance(validatorIndex)) { _enterMaintenance(validator, validatorIndex); } } - function felony(address validator) external initValidatorExtraSet override { + function felony(address validator) external override initValidatorExtraSet { require(msg.sender == SLASH_CONTRACT_ADDR || msg.sender == STAKE_HUB_ADDR, "only slash or stakeHub contract"); uint256 index = currentValidatorSetMap[validator]; @@ -784,34 +624,23 @@ contract BSCValidatorSet is IBSCValidatorSet, System, IParamSubscriber, IApplica } } - /*********************** For Temporary Maintenance **************************/ - /** - * @notice Return the index of the validator in `currentValidatorSet`(from 0 to `currentValidatorSet.length-1`) - */ - function getCurrentValidatorIndex(address validator) public view returns (uint256) { - uint256 index = currentValidatorSetMap[validator]; - require(index > 0, "only current validators"); - - // the actual index - return index - 1; - } - + /*----------------- For Temporary Maintenance -----------------*/ /** * @notice Return whether the validator at index could enter maintenance - */ + */ 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 + 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) - || getValidators().length <= 1 // - 6. check num of remaining working validators + || getValidators().length <= 1 // - 6. check num of remaining working validators ) { return false; } @@ -821,7 +650,7 @@ contract BSCValidatorSet is IBSCValidatorSet, System, IParamSubscriber, IApplica /** * @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) { @@ -838,27 +667,33 @@ contract BSCValidatorSet is IBSCValidatorSet, System, IParamSubscriber, IApplica /** * @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); + uint256 miningValidatorCount = getWorkingValidatorCount(); + _exitMaintenance(msg.sender, index, miningValidatorCount, true); } - /*********************** Param update ********************************/ - function updateParam(string calldata key, bytes calldata value) override external onlyInit onlyGov{ + /*----------------- Param update -----------------*/ + function updateParam(string calldata key, bytes calldata value) external override 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"); + 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.add(systemRewardRatio) <= BLOCK_FEES_RATIO_SCALE, "the burnRatio plus systemRewardRatio must be no greater than 10000"); + require( + newBurnRatio.add(systemRewardBaseRatio).add(systemRewardAntiMEVRatio) <= BLOCK_FEES_RATIO_SCALE, + "the burnRatio plus systemRewardBaseRatio and systemRewardAntiMEVRatio must be no greater than 10000" + ); burnRatio = newBurnRatio; } else if (Memory.compareStrings(key, "maxNumOfMaintaining")) { require(value.length == 32, "length of maxNumOfMaintaining mismatch"); @@ -872,12 +707,18 @@ contract BSCValidatorSet is IBSCValidatorSet, System, IParamSubscriber, IApplica } 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"); + 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"); + 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"); @@ -890,29 +731,221 @@ contract BSCValidatorSet is IBSCValidatorSet, System, IParamSubscriber, IApplica 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"); + require( + newNumOfCabinets <= MAX_NUM_OF_VALIDATORS, "the numOfCabinets must be less than MAX_NUM_OF_VALIDATORS" + ); numOfCabinets = newNumOfCabinets; - } else if (Memory.compareStrings(key, "systemRewardRatio")) { - require(value.length == 32, "length of systemRewardRatio mismatch"); - uint256 newSystemRewardRatio = BytesToTypes.bytesToUint256(32, value); - require(newSystemRewardRatio.add(burnRatio) <= BLOCK_FEES_RATIO_SCALE, "the systemRewardRatio plus burnRatio must be no greater than 10000"); - systemRewardRatio = newSystemRewardRatio; + } else if (Memory.compareStrings(key, "systemRewardBaseRatio")) { + require(value.length == 32, "length of systemRewardBaseRatio mismatch"); + uint256 newSystemRewardBaseRatio = BytesToTypes.bytesToUint256(32, value); + require( + newSystemRewardBaseRatio.add(burnRatio).add(systemRewardAntiMEVRatio) <= BLOCK_FEES_RATIO_SCALE, + "the systemRewardBaseRatio plus burnRatio and systemRewardAntiMEVRatio must be no greater than 10000" + ); + systemRewardBaseRatio = newSystemRewardBaseRatio; + } else if (Memory.compareStrings(key, "systemRewardAntiMEVRatio")) { + require(value.length == 32, "length of systemRewardAntiMEVRatio mismatch"); + uint256 newSystemRewardAntiMEVRatio = BytesToTypes.bytesToUint256(32, value); + require( + newSystemRewardAntiMEVRatio.add(burnRatio).add(systemRewardBaseRatio) <= BLOCK_FEES_RATIO_SCALE, + "the systemRewardAntiMEVRatio plus burnRatio and systemRewardBaseRatio must be no greater than 10000" + ); + systemRewardAntiMEVRatio = newSystemRewardAntiMEVRatio; + } else if (Memory.compareStrings(key, "turnLength")) { + require(value.length == 32, "length of turnLength mismatch"); + uint256 newTurnLength = BytesToTypes.bytesToUint256(32, value); + require( + newTurnLength >= 3 && newTurnLength <= 9 || newTurnLength == 1, + "the turnLength should be in [3,9] or equal to 1" + ); + turnLength = newTurnLength; } else { require(false, "unknown param"); } emit paramChange(key, value); } - /*********************** Internal Functions **************************/ + /*----------------- Internal Functions -----------------*/ + 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 (uint256 i; i < validatorSet.length; ++i) { + for (uint256 j; j < i; ++j) { + if (validatorSet[i].consensusAddress == validatorSet[j].consensusAddress) { + emit failReasonWithStr("duplicate consensus address of validatorSet"); + return ERROR_FAIL_CHECK_VALIDATORS; + } + } + } + } + + // step 0: force all maintaining validators to exit `Temporary Maintenance` + // - 1. validators exit maintenance + // - 2. clear all maintainInfo + // - 3. get unjailed validators from validatorSet + Validator[] memory validatorSetTemp; + bytes[] memory voteAddrsTemp; + { + // get migrated validators + Validator[] memory bscValidatorSet = _tmpMigratedValidatorSet; + bytes[] memory bscVoteAddrs = _tmpMigratedVoteAddrs; + for (uint256 i; i < bscValidatorSet.length; ++i) { + bscValidatorSet[i].votingPower = bscValidatorSet[i].votingPower * 3; // amplify the voting power for BSC validators + } + (Validator[] memory mergedValidators, bytes[] memory mergedVoteAddrs) = + _mergeValidatorSet(validatorSet, voteAddrs, bscValidatorSet, bscVoteAddrs); + + (validatorSetTemp, voteAddrsTemp) = _forceMaintainingValidatorsExit(mergedValidators, mergedVoteAddrs); + } + + { + //step 1: do calculate distribution, do not make it as an internal function for saving gas. + uint256 crossSize; + uint256 directSize; + uint256 validatorsNum = currentValidatorSet.length; + uint8[] memory isMigrated = new uint8[](validatorsNum); + for (uint256 i; i < validatorsNum; ++i) { + if ( + IStakeHub(STAKE_HUB_ADDR).consensusToOperator(currentValidatorSet[i].consensusAddress) != address(0) + ) { + isMigrated[i] = 1; + if (currentValidatorSet[i].incoming != 0) { + ++directSize; + } + } else if (currentValidatorSet[i].incoming >= 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 (uint256 i; i < validatorsNum; ++i) { + if (isMigrated[i] == 1) { + if (currentValidatorSet[i].incoming != 0) { + directAddrs[directSize] = payable(currentValidatorSet[i].consensusAddress); + directAmounts[directSize] = currentValidatorSet[i].incoming; + isMigrated[directSize] = 1; // directSize must be less than i. so we can use directSize as index + ++directSize; + } + } else if (currentValidatorSet[i].incoming >= 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; + isMigrated[directSize] = 0; + ++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 (uint256 i; i < crossIndexes.length; ++i) { + uint256 idx = crossIndexes[i]; + bool success = currentValidatorSet[idx].feeAddress.send(currentValidatorSet[idx].incoming); + if (success) { + emit directTransfer(currentValidatorSet[idx].feeAddress, currentValidatorSet[idx].incoming); + } else { + emit directTransferFail(currentValidatorSet[idx].feeAddress, currentValidatorSet[idx].incoming); + } + } + } + + // step 3: direct transfer + if (directAddrs.length > 0) { + for (uint256 i; i < directAddrs.length; ++i) { + if (isMigrated[i] == 1) { + IStakeHub(STAKE_HUB_ADDR).distributeReward{ value: directAmounts[i] }(directAddrs[i]); + } else { + bool success = directAddrs[i].send(directAmounts[i]); + if (success) { + emit directTransfer(directAddrs[i], directAmounts[i]); + } else { + emit directTransferFail(directAddrs[i], directAmounts[i]); + } + } + } + } + } + + for (uint256 i; i < currentValidatorSet.length; ++i) { + if (currentValidatorSet[i].incoming != 0) { + currentValidatorSet[i].incoming = 0; + } + } + + // step 4: do dusk transfer + if (address(this).balance > 0) { + 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; + } + function doUpdateState(Validator[] memory newValidatorSet, bytes[] memory newVoteAddrs) private { - uint n = currentValidatorSet.length; - uint m = newValidatorSet.length; + uint256 n = currentValidatorSet.length; + uint256 m = newValidatorSet.length; // delete stale validators - for (uint i; im) { - for (uint i=m; i m) { + for (uint256 i = m; i < n; ++i) { currentValidatorSet.pop(); validatorExtraSet.pop(); } } - uint k = n < m ? n:m; - for (uint i; in) { + if (m > n) { ValidatorExtra memory _validatorExtra; - for (uint i=n; i < m; ++i) { + for (uint256 i = n; i < m; ++i) { _validatorExtra.voteAddress = newVoteAddrs[i]; currentValidatorSet.push(newValidatorSet[i]); validatorExtraSet.push(_validatorExtra); - currentValidatorSetMap[newValidatorSet[i].consensusAddress] = i+1; + currentValidatorSetMap[newValidatorSet[i].consensusAddress] = i + 1; } } @@ -967,24 +1000,50 @@ contract BSCValidatorSet is IBSCValidatorSet, System, IParamSubscriber, IApplica // should not happen, still protect numOfMaintaining = 0; n = currentValidatorSet.length; - for (uint i; im) { - for (uint i=m; i m) { + for (uint256 i = m; i < n; ++i) { previousVoteAddrFullSet.pop(); } } - uint k = n < m ? n:m; - for (uint i; in) { - for (uint i=n; i < m; ++i) { + if (m > n) { + for (uint256 i = n; i < m; ++i) { previousVoteAddrFullSet.push(currentVoteAddrFullSet[i]); } } } function setCurrentVoteAddrFullSet() private { - uint n = currentVoteAddrFullSet.length; - uint m = validatorExtraSet.length; + uint256 n = currentVoteAddrFullSet.length; + uint256 m = validatorExtraSet.length; - if (n>m) { - for (uint i=m; i m) { + for (uint256 i = m; i < n; ++i) { currentVoteAddrFullSet.pop(); } } - uint k = n < m ? n:m; - for (uint i; in) { - for (uint i=n; i < m; ++i) { + if (m > n) { + for (uint256 i = n; i < m; ++i) { currentVoteAddrFullSet.push(validatorExtraSet[i].voteAddress); } } } - function isMonitoredForMaliciousVote(bytes calldata voteAddr) external override view returns (bool) { - uint m = currentVoteAddrFullSet.length; - for (uint i; i 0; --index) { - i = index - 1; // the actual index + for (uint256 index = currentValidatorSet.length; index > 0; --index) { + i = index - 1; // the actual index if (!validatorExtraSet[i].isMaintaining) { continue; } @@ -1150,7 +1219,7 @@ contract BSCValidatorSet is IBSCValidatorSet, System, IParamSubscriber, IApplica validator = currentValidatorSet[i].consensusAddress; // exit maintenance - isFelony = _exitMaintenance(validator, i, workingValidatorCount); + isFelony = _exitMaintenance(validator, i, miningValidatorCount, false); if (!isFelony) { continue; } @@ -1163,8 +1232,11 @@ contract BSCValidatorSet is IBSCValidatorSet, System, IParamSubscriber, IApplica } // record the jailed validator in validatorSet - for (uint j; j<_validatorSet.length; ++j) { - if (_validatorSet[j].consensusAddress == validator || _validatorSet[j].consensusAddress == latestConsensusAddress) { + for (uint256 j; j < _validatorSet.length; ++j) { + if ( + _validatorSet[j].consensusAddress == validator + || _validatorSet[j].consensusAddress == latestConsensusAddress + ) { _validatorSet[j].jailed = true; break; } @@ -1172,7 +1244,7 @@ contract BSCValidatorSet is IBSCValidatorSet, System, IParamSubscriber, IApplica } // count the number of felony validators - for (uint k; k<_validatorSet.length; ++k) { + for (uint256 k; k < _validatorSet.length; ++k) { if (_validatorSet[k].jailed || _validatorSet[k].consensusAddress == address(0)) { ++numOfFelony; } @@ -1190,7 +1262,7 @@ contract BSCValidatorSet is IBSCValidatorSet, System, IParamSubscriber, IApplica unjailedValidatorSet = new Validator[](_validatorSet.length - numOfFelony); unjailedVoteAddrs = new bytes[](_validatorSet.length - numOfFelony); i = 0; - for (uint index; index<_validatorSet.length; ++index) { + for (uint256 index; index < _validatorSet.length; ++index) { if (!_validatorSet[index].jailed && _validatorSet[index].consensusAddress != address(0)) { unjailedValidatorSet[i] = _validatorSet[index]; unjailedVoteAddrs[i] = _voteAddrs[index]; @@ -1209,26 +1281,35 @@ contract BSCValidatorSet is IBSCValidatorSet, System, IParamSubscriber, IApplica emit validatorEnterMaintenance(validator); } - function _exitMaintenance(address validator, uint index, uint256 workingValidatorCount) private returns (bool isFelony){ - if (maintainSlashScale == 0 || workingValidatorCount == 0 || numOfMaintaining == 0) { + function _exitMaintenance( + address validator, + uint256 index, + uint256 miningValidatorCount, + bool shouldRevert + ) private returns (bool isFelony) { + if (maintainSlashScale == 0 || miningValidatorCount == 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); - - // step2: slash the validator - (uint256 misdemeanorThreshold, uint256 felonyThreshold) = ISlashIndicator(SLASH_CONTRACT_ADDR).getSlashThresholds(); + uint256 slashCount = block.number.sub(validatorExtraSet[index].enterMaintenanceHeight).div(miningValidatorCount) + .div(maintainSlashScale); + + // step 2: clear isMaintaining info + validatorExtraSet[index].isMaintaining = false; + + // step 3: slash the validator + (uint256 misdemeanorThreshold, uint256 felonyThreshold) = + ISlashIndicator(SLASH_CONTRACT_ADDR).getSlashThresholds(); isFelony = false; if (slashCount >= felonyThreshold) { _felony(validator, index); if (IStakeHub(STAKE_HUB_ADDR).consensusToOperator(validator) != address(0)) { - ISlashIndicator(SLASH_CONTRACT_ADDR).downtimeSlash(validator, slashCount); + ISlashIndicator(SLASH_CONTRACT_ADDR).downtimeSlash(validator, slashCount, shouldRevert); } else { ISlashIndicator(SLASH_CONTRACT_ADDR).sendFelonyPackage(validator); } @@ -1237,14 +1318,15 @@ contract BSCValidatorSet is IBSCValidatorSet, System, IParamSubscriber, IApplica _misdemeanor(validator); } - // step 3: modify global storage - --numOfMaintaining; - validatorExtraSet[index].isMaintaining = false; - emit validatorExitMaintenance(validator); } - function _mergeValidatorSet(Validator[] memory validatorSet1, bytes[] memory voteAddrSet1, Validator[] memory validatorSet2, bytes[] memory voteAddrSet2) internal view returns (Validator[] memory, bytes[] memory) { + function _mergeValidatorSet( + Validator[] memory validatorSet1, + bytes[] memory voteAddrSet1, + Validator[] memory validatorSet2, + bytes[] memory voteAddrSet2 + ) internal view returns (Validator[] memory, bytes[] memory) { uint256 _length = IStakeHub(STAKE_HUB_ADDR).maxElectedValidators(); if (validatorSet1.length + validatorSet2.length < _length) { _length = validatorSet1.length + validatorSet2.length; @@ -1298,12 +1380,16 @@ contract BSCValidatorSet is IBSCValidatorSet, System, IParamSubscriber, IApplica } //rlp encode & decode function - function decodeValidatorSetSynPackage(bytes memory msgBytes) internal pure returns(IbcValidatorSetPackage memory, bool) { + 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; + uint256 idx = 0; while (iter.hasNext()) { if (idx == 0) { validatorSetPkg.packageType = uint8(iter.next().toUint()); @@ -1311,7 +1397,7 @@ contract BSCValidatorSet is IBSCValidatorSet, System, IParamSubscriber, IApplica RLPDecode.RLPItem[] memory items = iter.next().toList(); validatorSetPkg.validatorSet = new Validator[](items.length); validatorSetPkg.voteAddrs = new bytes[](items.length); - for (uint j; jscripts/init_holders.js + echo "replace BSCValidatorSet.sol" + sed "s/INIT_NUM_OF_CABINETS = 21/INIT_NUM_OF_CABINETS = ${INIT_NUM_OF_CABINETS}/g" contracts/BSCValidatorSet.sol >contracts/BSCValidatorSet.sol.out + mv contracts/BSCValidatorSet.sol.out contracts/BSCValidatorSet.sol + echo "replace generate.py" - sed "s/{{BLOCKS_PER_EPOCH}}/${BLOCKS_PER_EPOCH}/g" scripts/generate.py >scripts/generate.py.out1 - sed "s/{{INIT_NUM_OF_CABINETS}}/${INIT_NUM_OF_CABINETS}/g" scripts/generate.py.out1 >scripts/generate.py.out2 - sed "s/{{BSC_CHAIN_ID}}/${BSC_CHAIN_ID}/g" scripts/generate.py.out2 >scripts/generate.py + sed "s/dev_chain_id: int = 714/dev_chain_id: int = ${BSC_CHAIN_ID}/g" scripts/generate.py > scripts/generate.py.out + sed "s/epoch: str = \"200\"/epoch: str = \"${BLOCKS_PER_EPOCH}\"/g" scripts/generate.py.out > scripts/generate.py echo "start generate validators" node scripts/generate-validator.js echo "start generate process" /root/.local/bin/poetry run python3 scripts/generate.py dev + } function init_genesis_data() { diff --git a/e2e/chains/bsc/scripts/bsc-rpc.sh b/e2e/chains/bsc/scripts/bsc-rpc.sh index 5e44f39..f70eba4 100755 --- a/e2e/chains/bsc/scripts/bsc-rpc.sh +++ b/e2e/chains/bsc/scripts/bsc-rpc.sh @@ -15,4 +15,4 @@ done ETHSTATS="" geth --config ${DATA_DIR}/config.toml --datadir ${DATA_DIR} --netrestrict ${CLUSTER_CIDR} \ --state.scheme=hash --db.engine=leveldb --verbosity ${VERBOSE} --nousb ${ETHSTATS} \ - --unlock ${unlock_sequences} --password /dev/null --ipcpath /gethipc + --unlock ${unlock_sequences} --password /dev/null --ipcpath /gethipc --override.fixedturnlength 2 diff --git a/e2e/chains/bsc/scripts/bsc-validator.sh b/e2e/chains/bsc/scripts/bsc-validator.sh index c5127b0..2d2228c 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 --miner.etherbase=${VALIDATOR_ADDR} -unlock ${VALIDATOR_ADDR} --password /dev/null --blspassword /scripts/wallet_password.txt \ --light.serve 50 --pprof.addr 0.0.0.0 --metrics \ --rpc.allow-unprotected-txs --history.transactions 15768000 \ - --pprof --ipcpath /gethipc --vote + --pprof --ipcpath /gethipc --vote --override.fixedturnlength 2 diff --git a/module/facade.go b/module/facade.go index d0ae5bb..9b80618 100644 --- a/module/facade.go +++ b/module/facade.go @@ -16,10 +16,14 @@ func QueryFinalizedHeader(fn getHeaderFn, height uint64, limitHeight uint64) ([] return queryFinalizedHeader(fn, height, limitHeight) } -func QueryValidatorSet(fn getHeaderFn, height uint64) (Validators, error) { - return queryValidatorSet(fn, height) +func QueryValidatorSetAndTurnLength(fn getHeaderFn, height uint64) (Validators, uint8, error) { + return queryValidatorSetAndTurnLength(fn, height) } -func ExtractValidatorSet(h *types.Header) (Validators, error) { - return extractValidatorSet(h) +func ExtractValidatorSetAndTurnLength(h *types.Header) (Validators, uint8, error) { + return extractValidatorSetAndTurnLength(h) +} + +func MakeEpochHash(validators Validators, turnLength uint8) []byte { + return makeEpochHash(validators, turnLength) } diff --git a/module/header_query.go b/module/header_query.go index 538b5c4..209e651 100644 --- a/module/header_query.go +++ b/module/header_query.go @@ -70,25 +70,6 @@ func queryFinalizedHeader(fn getHeaderFn, height uint64, limitHeight uint64) ([] return nil, nil } -func queryFinalizedHeaderAfterCheckpoint(fn getHeaderFn, height uint64, limitHeight uint64, checkpoint uint64) ([]*ETHHeader, error) { - var ethHeaders []*ETHHeader - for i := height; i < checkpoint; i++ { - _, h, _, err := queryETHHeader(fn, i) - if err != nil { - return nil, err - } - ethHeaders = append(ethHeaders, h) - } - afterCheckpoint, err := queryFinalizedHeader(fn, checkpoint, limitHeight) - if err != nil { - return nil, err - } - if afterCheckpoint == nil { - return nil, nil - } - return append(ethHeaders, afterCheckpoint...), nil -} - func queryETHHeader(fn getHeaderFn, height uint64) (*types.Header, *ETHHeader, *VoteAttestation, error) { block, err := fn(context.TODO(), height) if err != nil { diff --git a/module/header_query_test.go b/module/header_query_test.go index 4df73f8..264cff6 100644 --- a/module/header_query_test.go +++ b/module/header_query_test.go @@ -20,6 +20,8 @@ func TestHeaderQueryTestSuite(t *testing.T) { } func (ts *HeaderQueryTestSuite) SetupTest() { + err := log.InitLogger("DEBUG", "text", "stdout") + ts.Require().NoError(err) } func (ts *HeaderQueryTestSuite) TestErrorQueryFinalizedHeader() { @@ -36,17 +38,14 @@ func (ts *HeaderQueryTestSuite) TestErrorQueryFinalizedHeader() { ts.Require().Nil(headers) fn = func(ctx context.Context, height uint64) (*types.Header, error) { - header := &types.Header{ - Number: big.NewInt(int64(height)), + h := headerByHeight(int64(height)) + if h != nil { + return h, nil } - if height == 31835601 || height == 31835602 { - header.Extra = common.Hex2Bytes("d88301020b846765746888676f312e32302e35856c696e7578000000b19df4a2f8b5831defffb860a44482b16993815ff4903016ce83ef788b455e2c80ba9976e8e55ac6591b9f9965234a0a2c579269bc5e09577977322d07d17bb8d657ac621a1abfadcb35b9c9d4713dbdd3d47fd3cc6dc2475c989aa224fecd083101049ef1adea2718b00e37f84c8401e5c5cfa0be938dfeafe5b932c2dcef0e2bebb1a05f31104a59b49d78b0b7746a483c14648401e5c5d0a03658f0bb6692995a9dd3b72a69ec6e8e1b9af4361718d8a275c2b92d26eeffc28027cb6d065d5a6d8749ca45a185add61b9ce470136898643170f8072513ca45f35d826f02cb2494f857beebdac9ec04196c8b30a65352ef155a28ac6a0057ff1601") - } - return header, nil + return &types.Header{Number: big.NewInt(int64(height))}, nil } - // No finalized header found ( invalid relation ) - headers, err = queryFinalizedHeader(fn, 31835592, 31835602) + headers, err = queryFinalizedHeader(fn, 360, 400) ts.Require().NoError(err) ts.Require().Nil(headers) } @@ -54,42 +53,34 @@ func (ts *HeaderQueryTestSuite) TestErrorQueryFinalizedHeader() { func (ts *HeaderQueryTestSuite) TestSuccessQueryFinalizedHeader() { ts.Require().NoError(log.InitLogger("INFO", "json", "stdout")) fn := func(ctx context.Context, height uint64) (*types.Header, error) { - header := &types.Header{ - Number: big.NewInt(int64(height)), + h := headerByHeight(int64(height)) + if h != nil { + return h, nil } - if height == 31835601 { - header.Extra = common.Hex2Bytes("d88301020b846765746888676f312e32302e35856c696e7578000000b19df4a2f8b5831defffb860a44482b16993815ff4903016ce83ef788b455e2c80ba9976e8e55ac6591b9f9965234a0a2c579269bc5e09577977322d07d17bb8d657ac621a1abfadcb35b9c9d4713dbdd3d47fd3cc6dc2475c989aa224fecd083101049ef1adea2718b00e37f84c8401e5c5cfa0be938dfeafe5b932c2dcef0e2bebb1a05f31104a59b49d78b0b7746a483c14648401e5c5d0a03658f0bb6692995a9dd3b72a69ec6e8e1b9af4361718d8a275c2b92d26eeffc28027cb6d065d5a6d8749ca45a185add61b9ce470136898643170f8072513ca45f35d826f02cb2494f857beebdac9ec04196c8b30a65352ef155a28ac6a0057ff1601") - } else if height == 31835602 { - header.Extra = common.Hex2Bytes("d88301020b846765746888676f312e31392e38856c696e7578000000b19df4a2f8b5831defffb860a244628caa7b3002a245b677c419c5991d9ba62e7d298e96565b72f8ccc6587510f8827c00783d0a13326bfc72bbcbb90e6bdf988ef662b286158296e0f270f21568fdb75210f631d53b81e74f0fa9a5c591dc46cbeceb28952264d8863b7812f84c8401e5c5d0a03658f0bb6692995a9dd3b72a69ec6e8e1b9af4361718d8a275c2b92d26eeffc28401e5c5d1a06b3b459206a5b6b1963e686318b0261b9c0888e1a253f77d109c60c6734c84c28031c42276b8ebf15bb5b843865147ea9435be29a83afeae646fc156b45832e0016bb3fa7119db6fe5dfe5d99733b6f7dd38ac4d7aeb7882cd4b6c576faf6951a901") - } - return header, nil + return &types.Header{Number: big.NewInt(int64(height))}, nil } - headers, err := queryFinalizedHeader(fn, 31835592, 31835602) + headers, err := queryFinalizedHeader(fn, 360, 402) ts.Require().NoError(err) - ts.Require().Len(headers, 11) + ts.Require().Len(headers, 402-360) } func (ts *HeaderQueryTestSuite) TestSuccessQueryLatestFinalizedHeader() { verify := func(latestBlockNumber uint64) { getHeader := func(ctx context.Context, height uint64) (*types.Header, error) { - header := &types.Header{ - Number: big.NewInt(int64(height)), - } - if height == 31835601 { - header.Extra = common.Hex2Bytes("d88301020b846765746888676f312e32302e35856c696e7578000000b19df4a2f8b5831defffb860a44482b16993815ff4903016ce83ef788b455e2c80ba9976e8e55ac6591b9f9965234a0a2c579269bc5e09577977322d07d17bb8d657ac621a1abfadcb35b9c9d4713dbdd3d47fd3cc6dc2475c989aa224fecd083101049ef1adea2718b00e37f84c8401e5c5cfa0be938dfeafe5b932c2dcef0e2bebb1a05f31104a59b49d78b0b7746a483c14648401e5c5d0a03658f0bb6692995a9dd3b72a69ec6e8e1b9af4361718d8a275c2b92d26eeffc28027cb6d065d5a6d8749ca45a185add61b9ce470136898643170f8072513ca45f35d826f02cb2494f857beebdac9ec04196c8b30a65352ef155a28ac6a0057ff1601") - } else if height == 31835602 { - header.Extra = common.Hex2Bytes("d88301020b846765746888676f312e31392e38856c696e7578000000b19df4a2f8b5831defffb860a244628caa7b3002a245b677c419c5991d9ba62e7d298e96565b72f8ccc6587510f8827c00783d0a13326bfc72bbcbb90e6bdf988ef662b286158296e0f270f21568fdb75210f631d53b81e74f0fa9a5c591dc46cbeceb28952264d8863b7812f84c8401e5c5d0a03658f0bb6692995a9dd3b72a69ec6e8e1b9af4361718d8a275c2b92d26eeffc28401e5c5d1a06b3b459206a5b6b1963e686318b0261b9c0888e1a253f77d109c60c6734c84c28031c42276b8ebf15bb5b843865147ea9435be29a83afeae646fc156b45832e0016bb3fa7119db6fe5dfe5d99733b6f7dd38ac4d7aeb7882cd4b6c576faf6951a901") + h := headerByHeight(int64(height)) + if h != nil { + return h, nil } - return header, nil + return &types.Header{Number: big.NewInt(int64(height))}, nil } height, h, err := queryLatestFinalizedHeader(getHeader, latestBlockNumber) ts.Require().NoError(err) ts.Require().Len(h, 3) - ts.Require().Equal(int(height), 31835600) + ts.Require().Equal(int(height), 401) } - for i := 31835602; i < 31835602+100; i++ { + for i := 403; i < 403+100; i++ { verify(uint64(i)) } } diff --git a/module/header_test.go b/module/header_test.go index 5c7c6a8..9474cc7 100644 --- a/module/header_test.go +++ b/module/header_test.go @@ -3,10 +3,8 @@ package module import ( "encoding/hex" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/rlp" "github.com/stretchr/testify/suite" - "math/big" "testing" ) @@ -22,12 +20,9 @@ func (ts *HeaderTestSuite) SetupTest() { } func (ts *HeaderTestSuite) TestNewHeaderSuccess() { - rawHeader := types.Header{ - Root: common.HexToHash("c84307dfe4ccfec4a851a77755d63228d8e0b9ba3345d1eee37ed729ee16eaa1"), - Number: big.NewInt(21400), - Extra: common.Hex2Bytes("d88301020a846765746888676f312e32302e35856c696e7578000000b19df4a2150bac492386862ad3df4b666bc096b0505bb694dab0bec348681af766751cb839576e9c515a09c8bffa30a46296ccc56612490eb480d03bf948e10005bbcc0421f90b3d4e2465176c461afb316ebc773c61faee85a6515daa8a923564c6ffd37fb2fe9f118ef88092e8762c7addb526ab7eb1e772baef85181f892c731be0c1891a50e6b06262c816295e26495cef6f69dfa69911d9d8e4f3bbadb89b977cf58294f7239d515e15b24cfeb82494056cf691eaf729b165f32c9757c429dba5051155903067e56ebe3698678e9135ebb5849518aff370ca25e19e1072cc1a9fabcaa7f3e2c0b4b16ad183c473bafe30a36e39fa4a143657e229cd23c77f8fbc8e4e4e241695dd3d248d1e51521eee6619143f349bbafec1551819b8be1efea2fc46ca749aa184248a459464eec1a21e7fc7b71a053d9644e9bb8da4853b8f872cd7c1d6b324bf1922829830646ceadfb658d3de009a61dd481a114a2e761c554b641742c973867899d38a80967d39e406a0a9642d41e9007a27fc1150a267d143a9f786cd2b5eecbdcc4036273705225b956d5e2f8f5eb95d2569c77a677c40c7fbea129d4b171a39b7a8ddabfab2317f59d86abfaf690850223d90e9e7593d91a29331dfc2f84d5adecc75fc39ecab4632c1b4400a3dd1e1298835bcca70f657164e5b75689b64b7fd1fa275f334f28e1896a26afa1295da81418593bd12814463d9f6e45c36a0e47eb4cd3e5b6af29c41e2a3a5636430155a466e216585af3ba772b61c6014342d914470ec7ac2975be345796c2b81db0422a5fd08e40db1fc2368d2245e4b18b1d0b85c921aaaafd2e341760e29fc613edd39f71254614e2055c3287a517ae2f5b9e386cd1b50a4550696d957cb4900f03ab84f83ff2df44193496793b847f64e9d6db1b3953682bb95edd096eb1e69bbd357c200992ca78050d0cbe180cfaa018e8b6c8fd93d6f4cea42bbb345dbc6f0dfdb5bec73a8a257074e82b881cfa06ef3eb4efeca060c2531359abd0eab8af1e3edfa2025fca464ac9c3fd123f6c24a0d78869485a6f79b60359f141df90a0c745125b131caaffd12b772e180fbf38a051c97dabc8aaa0126a233a9e828cdafcc7422c4bb1f4030a56ba364c54103f26bad91508b5220b741b218c5d6af1f979ac42bc68d98a5a0d796c6ab01b659ad0fbd9f515893fdd740b29ba0772dbde9b4635921dd91bd2963a0fc855e31f6338f45b211c4e9dedb7f2eb09de7b4dd66d7c2c7e57f628210187192fb89d4b99dd4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000be807dddb074639cd9fa61b47676c064fc50d62cb1f2c71577def3144fabeb75a8a1c8cb5b51d1d1b4a05eec67988b8685008baa17459ec425dbaebc852f496dc92196cdcc8e6d00c17eb431350c6c50d8b8f05176b90b11b3a3d4feb825ae9702711566df5dbf38e82add4dd1b573b95d2466fa6501ccb81e9d26a352b96150ccbf7b697fd0a419d1d6bf74282782b0b3eb1413c901d6ecf02e8e28939e8fb41b682372335be8070199ad3e8621d1743bcac4cc9d8f0f6e10f41e56461385c8eb5daac804fe3f2bca6ce739d93dbfb27e027f5e9e6da52b9e1c413ce35adc11000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ea0a6e3c511bbd10f4519ece37dc24887e11b55db2d4c6283c44a1c7bd503aaba7666e9f0c830e0ff016c1c750a5e48757a713d0836b1cabfd5c281b1de3b77d1c192183ee226379db83cffc681495730c11fdde79ba4c0cae7bc6faa3f0cc3e6093b633fd7ee4f86970926958d0b7ec80437f936acf212b78f0cd095f4565fff144fd458d233a5bef0274e31810c9df02f98fafde0f841f4e66a1cd000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f8b5830aefffb86097bc63a64e8d730014c39dcaac8f3309e37a11c06f0f5c233b55ba19c1f6c34d2d08de4b030ce825bb21fd884bc0fcb811336857419f5ca42a92ac149a4661a248de10f4ca6496069fdfd10d43bc74ccb81806b6ecd384617d1006b16dead7e4f84c8401dd8eaea0e61c6075d2ab24fcdc423764c21771cac6b241cbff89718f9cc8fc6459b4e7578401dd8eafa010c8358490a494a40c5c92aff8628fa770860a9d34e7fb7df38dfb208b0ddfc380ff15abfc44495e4d4605458bb485f0cac5a152b380a8d0208b3f9ff6216230ec4dd67a73b72b1d17a888c68e111f806ef0b255d012b5185b7420b5fb529c9b9300"), - } - ethHeader, err := newETHHeader(&rawHeader) + // 400 + rawHeader := fromRlp("f90442a04ec3c90370deeeab62de72108470bccac75d1abe118a778f01afa7a99c976a5da01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948fdaaa7e6631e438625ca25c857a3727ea28e565a08d30abd786d85a8a10ba441afafdf853b7fd2769351f6600402b88a1ac2d4d7aa0015ebe4a5d6cd56f0bf97db1d21746f59ab5cbecf216e34753920d815403ada2a03cd1ebc99cd975182c58de47be968c97658cff4c465e20654185f408a851403cb9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000028201908402625a008229a884669a6ce9b90223d98301040b846765746889676f312e32312e3132856c696e7578000020155b72048fdaaa7e6631e438625ca25c857a3727ea28e565b94a73be71b4a5703b4d0b36e4f65d52615b668b385efc047f7f385ace378981fa3750a0bc16ca6f8217be599bcfa274a7876ea32e7a748c697d01345145485561305b248cd0ede772633b8baea9958f9b602db36d78934d948244a13c2d66e998f987783276e9aee6facbff50b0d63574406b51b2e42bc54d19116d2348ac83461e2e0915d508ad921ebe99c27c8fdbd30aecdbe86f95aee2e06995f83ebeb327924669629f193ffd3257315c79ed5a4867ec53b502b5e6e04db2de85453e0936b441c339a26d10cfa71b50a50dd5edefbafd33740101d074b6d58b56a787a7644ddfff77d0c00f9e62cc58c931e671afc564f3f6e255cc6fc8a56701f8ae0fb8608b6dc552b410a6fa44fa31643850bcb314f1d4edb32c0c79ee3efef5397691f3685d80057d77510a00e77a39e8b2497419053c3b81a8901e85590a20a0a2dad529c82f6c175ec3ebca8a9112415aa94718af673c16c0e90e327e27709666e499f84882018ea0709f88597f05218c198818991cf5598c9280db30d5bfe899da9b7a8c963bff6c82018fa04ec3c90370deeeab62de72108470bccac75d1abe118a778f01afa7a99c976a5d8012518315e9c22a4a648f4d26efcf57f877a26498de6d53fe7a267e8d5ef01482009817fc9de90ca8008ef1f420aa606ddc0c56a975bace3906601fd5cde657d600a0000000000000000000000000000000000000000000000000000000000000000088000000000000000080a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b4218080") + ethHeader, err := newETHHeader(rawHeader) ts.Require().NoError(err) accountProof := []string{ @@ -45,12 +40,13 @@ func (ts *HeaderTestSuite) TestNewHeaderSuccess() { target, err := header.Target() ts.Require().NoError(err) ts.Require().Equal(target.Number, rawHeader.Number) - validator, err := ExtractValidatorSet(target) + validator, turnLength, err := extractValidatorSetAndTurnLength(target) ts.Require().NoError(err) - ts.Require().Equal(len(validator), 21) + ts.Require().Equal(len(validator), 4) + ts.Require().Equal(turnLength, uint8(1)) ts.Require().NoError(header.ValidateBasic()) ts.Require().Equal(header.GetHeight().GetRevisionHeight(), target.Number.Uint64()) - account, err := header.Account(common.HexToAddress(ibcHandlerAddress)) + account, err := header.Account(common.HexToAddress("aa43d337145e8930d01cb4e60abf6595c692921e")) ts.Require().NoError(err) ts.Require().Equal(account.Root, common.HexToHash("c3608871098f21b59607ef3fb9412a091de9246ad1281a92f5b07dc2f465b7a0")) ts.Require().Equal(account.CodeHash, common.Hex2Bytes("7498e14000b8457a51de3cd583e9337cfa52aee2c2e9f945fac35a820e685904")) diff --git a/module/lib_test.go b/module/lib_test.go new file mode 100644 index 0000000..572d8e3 --- /dev/null +++ b/module/lib_test.go @@ -0,0 +1,53 @@ +package module + +import ( + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/rlp" + "log" +) + +func fromRlp(hex string) *types.Header { + var h types.Header + err := rlp.DecodeBytes(common.Hex2Bytes(hex), &h) + if err != nil { + log.Fatal(err) + } + return &h +} + +func previousEpochHeader() *types.Header { + return fromRlp("f90391a0844dee9abff97d261ae0049fe38246ac10aba49f2b8618f28f7c2d19e62eccf9a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948fdaaa7e6631e438625ca25c857a3727ea28e565a0ecf1aa30fa754576ac4abc3cf2a61d1babd41c7e5515855efd857b2d3f37866ba00f0ea7d212c4aaca329b03f5e9ed9c69d3641eb5e03a4edb69b61e6f9d8d51efa0c3372a1f332fc4245e1a9fdcb62580fc6dae741087a8029560f19216dd3d58b9b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000281c88402625a00826c7484669a6a91b90173d98301040b846765746889676f312e32312e3132856c696e7578000020155b72048fdaaa7e6631e438625ca25c857a3727ea28e565b94a73be71b4a5703b4d0b36e4f65d52615b668b385efc047f7f385ace378981fa3750a0bc16ca6f8217be599bcfa274b2e42bc54d19116d2348ac83461e2e0915d508ad921ebe99c27c8fdbd30aecdbe86f95aee2e06995f83ebeb327924669629f193ffd3257315c79ed5a4867ec53b502b5e6d9a13701eafb76870cb220843b8c6476824bfa158c66a3f3d2fba1d440da8edc79b59ed9a3a43db62bd7659f7d4e25073f9241dba560600b23e26c30d48ea0395eeeb4ede04db2de85453e0936b441c339a26d10cfa71b50a50dd5edefbafd33740101d074b6d58b56a787a7644ddfff77d0c00f9e62cc58c931e671afc564f3f6e255cc6fc8a567015cbc63c3d778cef5e8dbfdaf1fd8f758a764f2667aad2d3775954e4ac23e726226b66f0a94631bd0b6d937b22955d73eed65a31a6f535662f51cc7547143f6f201a0000000000000000000000000000000000000000000000000000000000000000088000000000000000080a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b4218080") +} + +func epochHeader() *types.Header { + return fromRlp("f90442a04ec3c90370deeeab62de72108470bccac75d1abe118a778f01afa7a99c976a5da01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948fdaaa7e6631e438625ca25c857a3727ea28e565a08d30abd786d85a8a10ba441afafdf853b7fd2769351f6600402b88a1ac2d4d7aa0015ebe4a5d6cd56f0bf97db1d21746f59ab5cbecf216e34753920d815403ada2a03cd1ebc99cd975182c58de47be968c97658cff4c465e20654185f408a851403cb9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000028201908402625a008229a884669a6ce9b90223d98301040b846765746889676f312e32312e3132856c696e7578000020155b72048fdaaa7e6631e438625ca25c857a3727ea28e565b94a73be71b4a5703b4d0b36e4f65d52615b668b385efc047f7f385ace378981fa3750a0bc16ca6f8217be599bcfa274a7876ea32e7a748c697d01345145485561305b248cd0ede772633b8baea9958f9b602db36d78934d948244a13c2d66e998f987783276e9aee6facbff50b0d63574406b51b2e42bc54d19116d2348ac83461e2e0915d508ad921ebe99c27c8fdbd30aecdbe86f95aee2e06995f83ebeb327924669629f193ffd3257315c79ed5a4867ec53b502b5e6e04db2de85453e0936b441c339a26d10cfa71b50a50dd5edefbafd33740101d074b6d58b56a787a7644ddfff77d0c00f9e62cc58c931e671afc564f3f6e255cc6fc8a56701f8ae0fb8608b6dc552b410a6fa44fa31643850bcb314f1d4edb32c0c79ee3efef5397691f3685d80057d77510a00e77a39e8b2497419053c3b81a8901e85590a20a0a2dad529c82f6c175ec3ebca8a9112415aa94718af673c16c0e90e327e27709666e499f84882018ea0709f88597f05218c198818991cf5598c9280db30d5bfe899da9b7a8c963bff6c82018fa04ec3c90370deeeab62de72108470bccac75d1abe118a778f01afa7a99c976a5d8012518315e9c22a4a648f4d26efcf57f877a26498de6d53fe7a267e8d5ef01482009817fc9de90ca8008ef1f420aa606ddc0c56a975bace3906601fd5cde657d600a0000000000000000000000000000000000000000000000000000000000000000088000000000000000080a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b4218080") +} + +func epochHeaderPlus1() *types.Header { + return fromRlp("f9032ea0e256fac4dd62cc71eaefd8d6c24ae5209c0e48f5c0b62bcced06dfa838c2ad31a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794b2e42bc54d19116d2348ac83461e2e0915d508ada08d30abd786d85a8a10ba441afafdf853b7fd2769351f6600402b88a1ac2d4d7aa056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000028201918402625a008084669a6cecb90111d98301040b846765746889676f312e32312e3132856c696e7578000020155b72f8ae0fb8609338bf42b6ef715e9c887e1b285e706355c2a993cd227497b447f8aad4b7fa44d18cd895862e1a2b961b78656d620f9c015e777cf9bcb6c50e1db2783818bd91f647f6879f8bd199f266f1166f9241f00f955fb5210e7e89e7678680900d1cc1f84882018fa04ec3c90370deeeab62de72108470bccac75d1abe118a778f01afa7a99c976a5d820190a0e256fac4dd62cc71eaefd8d6c24ae5209c0e48f5c0b62bcced06dfa838c2ad3180d6c559fceda3795918a2fdd34cb4f77608c8095b67091aadcef5d5c4efe09fc0477a1977c0037f19244240648637c3c5ec9fe22f1db4899a022575bec96cfccf01a0000000000000000000000000000000000000000000000000000000000000000088000000000000000080a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b4218080") +} + +func epochHeaderPlus2() *types.Header { + return fromRlp("f9032ea0669cf9fc3b3d480d7a8de1cc051e1d95fa24be8870aa93bb5bfc03f1d592db46a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794d9a13701eafb76870cb220843b8c6476824bfa15a08d30abd786d85a8a10ba441afafdf853b7fd2769351f6600402b88a1ac2d4d7aa056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000028201928402625a008084669a6cefb90111d98301040b846765746889676f312e32312e3132856c696e7578000020155b72f8ae0fb8608d465cf004274c6caaddd041116c93f12cba458536d23efc6148134af357a685c7b84b1d3de59eb61b2756e7b99a99de00a6158245e16d23dd10602ef719836ce41862c567745727a145df4bde737415e8ffbec5056d4653b02fe1ddc8f21069f848820190a0e256fac4dd62cc71eaefd8d6c24ae5209c0e48f5c0b62bcced06dfa838c2ad31820191a0669cf9fc3b3d480d7a8de1cc051e1d95fa24be8870aa93bb5bfc03f1d592db468083bec325b33996ad2fc35e146d7e8fd215177b1423378d3b07cb73293d5384733488a981b64ae03cbcf44af281cfbd57431addbd8432042c49fb4c78d5573f0d01a0000000000000000000000000000000000000000000000000000000000000000088000000000000000080a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b4218080") +} + +func epochHeaderPlus3() *types.Header { + return fromRlp("f9032ea0705444384ac2acf605c4ca8353e5070f37cc0976597dfdfc74413e278725eee7a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794e04db2de85453e0936b441c339a26d10cfa71b50a08d30abd786d85a8a10ba441afafdf853b7fd2769351f6600402b88a1ac2d4d7aa056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000028201938402625a008084669a6cf2b90111d98301040b846765746889676f312e32312e3132856c696e7578000020155b72f8ae0fb860a6e88879bc7f8ff4ee90ba0776b414b97ffcb0a2bc4f9484075ea121e00b7ce27e21c0fbf76f34746b232e76a37cfc220011efbd7863237e75eb2830748736e9092847a283401bf6793e94d00619764884d012609cf5bace403e93b66f60c3bcf848820191a0669cf9fc3b3d480d7a8de1cc051e1d95fa24be8870aa93bb5bfc03f1d592db46820192a0705444384ac2acf605c4ca8353e5070f37cc0976597dfdfc74413e278725eee780f5171f7fc98ba3118543b55677128c397b07085a29dcd71c989c7f0eb602308342cf64470f85ebe31ebdda4244e7992b82ff2026ac461d0f2997332ccb99255201a0000000000000000000000000000000000000000000000000000000000000000088000000000000000080a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b4218080") +} + +func headerByHeight(height int64) *types.Header { + switch height { + case 200: + return previousEpochHeader() + case 400: + return epochHeader() + case 401: + return epochHeaderPlus1() + case 402: + return epochHeaderPlus2() + case 403: + return epochHeaderPlus3() + } + return nil +} diff --git a/module/parlia.pb.go b/module/parlia.pb.go index e94a002..278b592 100644 --- a/module/parlia.pb.go +++ b/module/parlia.pb.go @@ -114,6 +114,8 @@ type Header struct { AccountProof []byte `protobuf:"bytes,3,opt,name=account_proof,json=accountProof,proto3" json:"account_proof,omitempty"` CurrentValidators [][]byte `protobuf:"bytes,4,rep,name=current_validators,json=currentValidators,proto3" json:"current_validators,omitempty"` PreviousValidators [][]byte `protobuf:"bytes,5,rep,name=previous_validators,json=previousValidators,proto3" json:"previous_validators,omitempty"` + CurrentTurnLength uint32 `protobuf:"varint,6,opt,name=current_turn_length,json=currentTurnLength,proto3" json:"current_turn_length,omitempty"` + PreviousTurnLength uint32 `protobuf:"varint,7,opt,name=previous_turn_length,json=previousTurnLength,proto3" json:"previous_turn_length,omitempty"` } func (m *Header) Reset() { *m = Header{} } @@ -241,51 +243,54 @@ func init() { } var fileDescriptor_dc631224085c6c85 = []byte{ - // 702 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x54, 0xcd, 0x4e, 0x23, 0x47, - 0x10, 0xf6, 0x18, 0x63, 0xec, 0xc6, 0x06, 0xd1, 0x21, 0x64, 0x70, 0x92, 0xc1, 0x32, 0x8a, 0x62, - 0x45, 0x62, 0x26, 0x76, 0xa4, 0x28, 0x97, 0x08, 0x81, 0x89, 0x64, 0x94, 0x20, 0xa1, 0x21, 0xca, - 0x21, 0x97, 0x51, 0x4f, 0x4f, 0xdb, 0xd3, 0xda, 0x99, 0x69, 0xab, 0xbb, 0xc7, 0x62, 0xf7, 0x29, - 0x76, 0x6f, 0xfb, 0x0a, 0xfb, 0x14, 0x7b, 0xe5, 0xc8, 0x71, 0x4f, 0xfb, 0x03, 0x6f, 0xb1, 0xa7, - 0x55, 0xff, 0x18, 0x58, 0xb1, 0xbf, 0xb7, 0xaa, 0xaf, 0xbe, 0xaf, 0x54, 0xf5, 0xd5, 0xf4, 0x80, - 0x9f, 0x69, 0x8c, 0x83, 0x8c, 0x4e, 0x53, 0x89, 0x33, 0x4a, 0x0a, 0x29, 0x82, 0x19, 0xe2, 0x19, - 0x45, 0xc1, 0x7c, 0x60, 0x23, 0x7f, 0xc6, 0x99, 0x64, 0xb0, 0x43, 0x63, 0xec, 0xdf, 0x25, 0xfa, - 0xb6, 0x3c, 0x1f, 0x74, 0x36, 0xa7, 0x6c, 0xca, 0x34, 0x2d, 0x50, 0x91, 0x51, 0x74, 0x76, 0x54, - 0x6b, 0xcc, 0x38, 0x09, 0x8c, 0x42, 0xb5, 0x34, 0x91, 0x25, 0x78, 0x53, 0xc6, 0xa6, 0x19, 0x09, - 0x74, 0x16, 0x97, 0x93, 0x20, 0x29, 0x39, 0x92, 0x94, 0x15, 0xa6, 0xde, 0x7b, 0x5b, 0x05, 0xab, - 0x23, 0x2d, 0x38, 0x93, 0x48, 0x12, 0xb8, 0x0d, 0x1a, 0x38, 0x45, 0xb4, 0x88, 0x68, 0xe2, 0x3a, - 0x5d, 0xa7, 0x5f, 0x0b, 0x57, 0x74, 0x7e, 0x9c, 0xc0, 0x5f, 0xc0, 0x06, 0x8d, 0x71, 0x24, 0x24, - 0xe3, 0x24, 0x42, 0x49, 0xc2, 0x89, 0x10, 0x6e, 0xb5, 0xeb, 0xf4, 0x5b, 0xe1, 0x3a, 0x8d, 0xf1, - 0x99, 0xc2, 0x0f, 0x0c, 0x0c, 0x7f, 0x05, 0x9b, 0x8a, 0x8b, 0x59, 0x9e, 0x53, 0x99, 0xab, 0x55, - 0x22, 0x91, 0x31, 0xe9, 0x2e, 0x69, 0x3a, 0xa4, 0x31, 0x1e, 0xdd, 0x96, 0xce, 0x32, 0x26, 0xe1, - 0x3e, 0x68, 0x67, 0x48, 0x12, 0x21, 0xa3, 0x94, 0x28, 0x07, 0xdc, 0x5a, 0xd7, 0xe9, 0xaf, 0x0e, - 0x3b, 0xbe, 0xf2, 0x44, 0x6d, 0xe8, 0xdb, 0xbd, 0xe6, 0x03, 0x7f, 0xac, 0x19, 0x61, 0xcb, 0x08, - 0x4c, 0x06, 0xff, 0x01, 0xeb, 0x92, 0x97, 0x42, 0xd2, 0x62, 0x1a, 0xcd, 0x08, 0xa7, 0x2c, 0x71, - 0x97, 0x75, 0x8b, 0x6d, 0xdf, 0x78, 0xe0, 0x2f, 0x3c, 0xf0, 0x8f, 0xac, 0x07, 0x87, 0x8d, 0x8b, - 0x97, 0x3b, 0x95, 0xa7, 0xaf, 0x76, 0x9c, 0x70, 0x6d, 0xa1, 0x3d, 0xd5, 0x52, 0xf8, 0x37, 0x58, - 0xcf, 0xd1, 0x79, 0x84, 0x33, 0x86, 0x1f, 0x44, 0x09, 0xa7, 0x13, 0xe9, 0xd6, 0xbf, 0xbc, 0x5b, - 0x3b, 0x47, 0xe7, 0x23, 0x25, 0x3d, 0x52, 0x4a, 0xb8, 0x05, 0xea, 0x13, 0xce, 0x1e, 0x91, 0xc2, - 0x5d, 0xe9, 0x3a, 0xfd, 0x46, 0x68, 0xb3, 0xde, 0x2e, 0x68, 0xfe, 0xf5, 0xef, 0x78, 0x4c, 0x50, - 0x42, 0xb8, 0x22, 0xa5, 0x3a, 0xd2, 0xbe, 0xb7, 0x42, 0x9b, 0xf5, 0x9e, 0x54, 0x41, 0xdd, 0x52, - 0xf6, 0xc1, 0x8a, 0x01, 0x85, 0xeb, 0x74, 0x97, 0xfa, 0xab, 0xc3, 0x9f, 0xfc, 0x8f, 0x7f, 0x31, - 0xfe, 0x4d, 0xeb, 0x70, 0xa1, 0x82, 0x07, 0xc0, 0xec, 0x49, 0x92, 0x85, 0xcb, 0xd5, 0xcf, 0xba, - 0xdc, 0xb6, 0x0a, 0x6b, 0xf3, 0x2e, 0x68, 0x23, 0x8c, 0x59, 0x59, 0xc8, 0x68, 0xc6, 0x19, 0x9b, - 0xd8, 0x93, 0xb6, 0x2c, 0x78, 0xaa, 0x30, 0xb8, 0x07, 0x20, 0x2e, 0x39, 0x27, 0x85, 0x8c, 0xe6, - 0x28, 0xa3, 0x09, 0x92, 0x8c, 0x0b, 0xb7, 0xd6, 0x5d, 0xea, 0xb7, 0xc2, 0x0d, 0x5b, 0xf9, 0xef, - 0xa6, 0x00, 0x03, 0xf0, 0xcd, 0x8c, 0x93, 0x39, 0x65, 0xa5, 0xb8, 0xcb, 0x5f, 0xd6, 0x7c, 0xb8, - 0x28, 0xdd, 0x0a, 0x7a, 0xcf, 0x1d, 0xb0, 0x36, 0x62, 0x85, 0x20, 0x85, 0x28, 0x85, 0xf9, 0x70, - 0x7f, 0x04, 0x40, 0xa8, 0x20, 0xe2, 0x8c, 0x49, 0x6b, 0x61, 0x53, 0x23, 0x21, 0x63, 0x12, 0xfe, - 0x00, 0x9a, 0x92, 0xe6, 0x44, 0x48, 0x94, 0xcf, 0xf4, 0xd2, 0xb5, 0xf0, 0x16, 0x80, 0xbf, 0x83, - 0xef, 0xee, 0xcf, 0x1b, 0xa5, 0x48, 0xa4, 0x76, 0xbd, 0x6f, 0xef, 0x0d, 0x3d, 0x46, 0x22, 0x85, - 0x7f, 0x00, 0xf7, 0x03, 0x83, 0x1b, 0x61, 0x4d, 0x0b, 0xb7, 0xee, 0x4f, 0xaf, 0x94, 0xbd, 0x67, - 0x0e, 0x68, 0x9d, 0x50, 0x11, 0x93, 0x14, 0xa9, 0x32, 0x87, 0xdf, 0x83, 0xa6, 0xb1, 0x7e, 0xf1, - 0xf2, 0x9a, 0x61, 0xc3, 0x00, 0xc7, 0x09, 0xfc, 0x13, 0x34, 0xcc, 0x09, 0xa3, 0x81, 0xbd, 0x58, - 0xef, 0x53, 0x97, 0x7f, 0xff, 0xec, 0x83, 0x3b, 0xf2, 0xa1, 0xde, 0xe7, 0xab, 0xe4, 0xc3, 0xc3, - 0x93, 0x8b, 0x37, 0x5e, 0xe5, 0xe2, 0xca, 0x73, 0x2e, 0xaf, 0x3c, 0xe7, 0xf5, 0x95, 0xe7, 0x3c, - 0xbe, 0xf6, 0x2a, 0x97, 0xd7, 0x5e, 0xe5, 0xc5, 0xb5, 0x57, 0xf9, 0x3f, 0x98, 0x52, 0x99, 0x96, - 0xb1, 0x8f, 0x59, 0x1e, 0x24, 0x48, 0x22, 0xfd, 0xbb, 0xc8, 0x50, 0x1c, 0xd0, 0x18, 0xef, 0x99, - 0xa6, 0x7b, 0x9c, 0x64, 0xe8, 0x61, 0x90, 0xb3, 0xa4, 0xcc, 0x48, 0x5c, 0xd7, 0x2f, 0xe7, 0xb7, - 0x77, 0x01, 0x00, 0x00, 0xff, 0xff, 0x07, 0x09, 0x35, 0x20, 0x17, 0x05, 0x00, 0x00, + // 739 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x94, 0xcd, 0x6e, 0xeb, 0x44, + 0x14, 0xc7, 0xe3, 0x34, 0x37, 0x1f, 0xd3, 0xe4, 0x56, 0x77, 0x6e, 0x29, 0x6e, 0x00, 0x37, 0x4a, + 0x85, 0x88, 0x90, 0x6a, 0x93, 0x20, 0x21, 0x36, 0xa8, 0x6a, 0x53, 0xa4, 0x54, 0xb4, 0x52, 0xe5, + 0x56, 0x2c, 0xd8, 0x58, 0xe3, 0xf1, 0xc4, 0x1e, 0x61, 0x7b, 0xa2, 0x99, 0x71, 0x54, 0x78, 0x0a, + 0x96, 0xbc, 0x02, 0x4f, 0xc1, 0xb6, 0xcb, 0x2e, 0x59, 0xf1, 0xd1, 0x3e, 0x02, 0x3b, 0x56, 0x68, + 0x3e, 0x92, 0x06, 0x95, 0xaf, 0xbb, 0x9b, 0x73, 0xce, 0xff, 0x77, 0xac, 0xf3, 0x9f, 0x33, 0x06, + 0x1f, 0xd0, 0x18, 0x07, 0x39, 0x4d, 0x33, 0x89, 0x73, 0x4a, 0x4a, 0x29, 0x82, 0x05, 0xe2, 0x39, + 0x45, 0xc1, 0x72, 0x6c, 0x4f, 0xfe, 0x82, 0x33, 0xc9, 0x60, 0x9f, 0xc6, 0xd8, 0xdf, 0x14, 0xfa, + 0xb6, 0xbc, 0x1c, 0xf7, 0x77, 0x53, 0x96, 0x32, 0x2d, 0x0b, 0xd4, 0xc9, 0x10, 0xfd, 0x03, 0xd5, + 0x1a, 0x33, 0x4e, 0x02, 0x43, 0xa8, 0x96, 0xe6, 0x64, 0x05, 0x5e, 0xca, 0x58, 0x9a, 0x93, 0x40, + 0x47, 0x71, 0x35, 0x0f, 0x92, 0x8a, 0x23, 0x49, 0x59, 0x69, 0xea, 0xc3, 0x3f, 0xea, 0x60, 0x7b, + 0xaa, 0x81, 0x6b, 0x89, 0x24, 0x81, 0xfb, 0xa0, 0x8d, 0x33, 0x44, 0xcb, 0x88, 0x26, 0xae, 0x33, + 0x70, 0x46, 0x8d, 0xb0, 0xa5, 0xe3, 0xf3, 0x04, 0x7e, 0x08, 0x5e, 0xd1, 0x18, 0x47, 0x42, 0x32, + 0x4e, 0x22, 0x94, 0x24, 0x9c, 0x08, 0xe1, 0xd6, 0x07, 0xce, 0xa8, 0x1b, 0xee, 0xd0, 0x18, 0x5f, + 0xab, 0xfc, 0x89, 0x49, 0xc3, 0x8f, 0xc0, 0xae, 0xd2, 0x62, 0x56, 0x14, 0x54, 0x16, 0x6a, 0x94, + 0x48, 0xe4, 0x4c, 0xba, 0x5b, 0x5a, 0x0e, 0x69, 0x8c, 0xa7, 0x4f, 0xa5, 0xeb, 0x9c, 0x49, 0x78, + 0x0c, 0x7a, 0x39, 0x92, 0x44, 0xc8, 0x28, 0x23, 0xca, 0x01, 0xb7, 0x31, 0x70, 0x46, 0xdb, 0x93, + 0xbe, 0xaf, 0x3c, 0x51, 0x13, 0xfa, 0x76, 0xae, 0xe5, 0xd8, 0x9f, 0x69, 0x45, 0xd8, 0x35, 0x80, + 0x89, 0xe0, 0x05, 0xd8, 0x91, 0xbc, 0x12, 0x92, 0x96, 0x69, 0xb4, 0x20, 0x9c, 0xb2, 0xc4, 0x7d, + 0xa1, 0x5b, 0xec, 0xfb, 0xc6, 0x03, 0x7f, 0xe5, 0x81, 0x7f, 0x66, 0x3d, 0x38, 0x6d, 0xdf, 0xfd, + 0x7c, 0x50, 0xfb, 0xfe, 0x97, 0x03, 0x27, 0x7c, 0xb9, 0x62, 0xaf, 0x34, 0x0a, 0xbf, 0x00, 0x3b, + 0x05, 0xba, 0x8d, 0x70, 0xce, 0xf0, 0xd7, 0x51, 0xc2, 0xe9, 0x5c, 0xba, 0xcd, 0xff, 0xdf, 0xad, + 0x57, 0xa0, 0xdb, 0xa9, 0x42, 0xcf, 0x14, 0x09, 0xf7, 0x40, 0x73, 0xce, 0xd9, 0xb7, 0xa4, 0x74, + 0x5b, 0x03, 0x67, 0xd4, 0x0e, 0x6d, 0x34, 0x3c, 0x04, 0x9d, 0xcf, 0x6f, 0x66, 0x33, 0x82, 0x12, + 0xc2, 0x95, 0x28, 0xd3, 0x27, 0xed, 0x7b, 0x37, 0xb4, 0xd1, 0xf0, 0xf7, 0x3a, 0x68, 0x5a, 0xc9, + 0x31, 0x68, 0x99, 0xa4, 0x70, 0x9d, 0xc1, 0xd6, 0x68, 0x7b, 0xf2, 0xbe, 0xff, 0xcf, 0x1b, 0xe3, + 0xaf, 0x5b, 0x87, 0x2b, 0x0a, 0x9e, 0x00, 0x33, 0x27, 0x49, 0x56, 0x2e, 0xd7, 0xff, 0xd3, 0xe5, + 0x9e, 0x25, 0xac, 0xcd, 0x87, 0xa0, 0x87, 0x30, 0x66, 0x55, 0x29, 0xa3, 0x05, 0x67, 0x6c, 0x6e, + 0xaf, 0xb4, 0x6b, 0x93, 0x57, 0x2a, 0x07, 0x8f, 0x00, 0xc4, 0x15, 0xe7, 0xa4, 0x94, 0xd1, 0x12, + 0xe5, 0x34, 0x41, 0x92, 0x71, 0xe1, 0x36, 0x06, 0x5b, 0xa3, 0x6e, 0xf8, 0xca, 0x56, 0xbe, 0x5c, + 0x17, 0x60, 0x00, 0x5e, 0x2f, 0x38, 0x59, 0x52, 0x56, 0x89, 0x4d, 0xfd, 0x0b, 0xad, 0x87, 0xab, + 0xd2, 0x06, 0xe0, 0x83, 0xd7, 0xab, 0xfe, 0xb2, 0xe2, 0x65, 0x94, 0x93, 0x32, 0x95, 0x99, 0xbe, + 0xa1, 0xde, 0xfa, 0x03, 0x37, 0x15, 0x2f, 0x2f, 0x74, 0x41, 0xad, 0xe3, 0xfa, 0x03, 0x9b, 0x40, + 0x4b, 0x03, 0xeb, 0x2f, 0x3c, 0x11, 0xc3, 0x1f, 0x1d, 0xf0, 0x72, 0xca, 0x4a, 0x41, 0x4a, 0x51, + 0x09, 0xf3, 0x34, 0xde, 0x03, 0x40, 0xa8, 0x43, 0xc4, 0x19, 0x93, 0xf6, 0x92, 0x3a, 0x3a, 0x13, + 0x32, 0x26, 0xe1, 0xbb, 0xa0, 0x23, 0x69, 0x41, 0x84, 0x44, 0xc5, 0x42, 0xdb, 0xda, 0x08, 0x9f, + 0x12, 0xf0, 0x13, 0xf0, 0xf6, 0x73, 0x47, 0xa2, 0x0c, 0x89, 0xcc, 0x1a, 0xf8, 0xd6, 0x33, 0x5b, + 0x66, 0x48, 0x64, 0xf0, 0x53, 0xe0, 0xfe, 0x8d, 0x35, 0x06, 0x6c, 0x68, 0x70, 0xef, 0xb9, 0x3f, + 0x8a, 0x1c, 0xfe, 0xe0, 0x80, 0xee, 0x25, 0x15, 0x31, 0xc9, 0x90, 0x2a, 0x73, 0xf8, 0x0e, 0xe8, + 0x98, 0xcb, 0x5d, 0xbd, 0xed, 0x4e, 0xd8, 0x36, 0x89, 0xf3, 0x04, 0x7e, 0x06, 0xda, 0x66, 0x49, + 0xa2, 0xb1, 0xdd, 0x89, 0xe1, 0xbf, 0xed, 0xd6, 0x5f, 0x17, 0x6b, 0xbc, 0x81, 0x4f, 0xf4, 0x3c, + 0x6f, 0x84, 0x4f, 0x4e, 0x2f, 0xef, 0x7e, 0xf3, 0x6a, 0x77, 0x0f, 0x9e, 0x73, 0xff, 0xe0, 0x39, + 0xbf, 0x3e, 0x78, 0xce, 0x77, 0x8f, 0x5e, 0xed, 0xfe, 0xd1, 0xab, 0xfd, 0xf4, 0xe8, 0xd5, 0xbe, + 0x0a, 0x52, 0x2a, 0xb3, 0x2a, 0xf6, 0x31, 0x2b, 0x82, 0x04, 0x49, 0xa4, 0x7f, 0x48, 0x39, 0x8a, + 0x03, 0x1a, 0xe3, 0x23, 0xd3, 0xf4, 0x88, 0x93, 0x1c, 0x7d, 0x13, 0x14, 0x2c, 0xa9, 0x72, 0x12, + 0x37, 0xf5, 0xdb, 0xfc, 0xf8, 0xcf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x73, 0x6e, 0xaa, 0x9e, 0x79, + 0x05, 0x00, 0x00, } func (m *ClientState) Marshal() (dAtA []byte, err error) { @@ -418,6 +423,16 @@ func (m *Header) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.PreviousTurnLength != 0 { + i = encodeVarintParlia(dAtA, i, uint64(m.PreviousTurnLength)) + i-- + dAtA[i] = 0x38 + } + if m.CurrentTurnLength != 0 { + i = encodeVarintParlia(dAtA, i, uint64(m.CurrentTurnLength)) + i-- + dAtA[i] = 0x30 + } if len(m.PreviousValidators) > 0 { for iNdEx := len(m.PreviousValidators) - 1; iNdEx >= 0; iNdEx-- { i -= len(m.PreviousValidators[iNdEx]) @@ -662,6 +677,12 @@ func (m *Header) Size() (n int) { n += 1 + l + sovParlia(uint64(l)) } } + if m.CurrentTurnLength != 0 { + n += 1 + sovParlia(uint64(m.CurrentTurnLength)) + } + if m.PreviousTurnLength != 0 { + n += 1 + sovParlia(uint64(m.PreviousTurnLength)) + } return n } @@ -1256,6 +1277,44 @@ func (m *Header) Unmarshal(dAtA []byte) error { m.PreviousValidators = append(m.PreviousValidators, make([]byte, postIndex-iNdEx)) copy(m.PreviousValidators[len(m.PreviousValidators)-1], dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 6: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field CurrentTurnLength", wireType) + } + m.CurrentTurnLength = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowParlia + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.CurrentTurnLength |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 7: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field PreviousTurnLength", wireType) + } + m.PreviousTurnLength = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowParlia + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.PreviousTurnLength |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipParlia(dAtA[iNdEx:]) diff --git a/module/proof.go b/module/proof.go index 2a4a311..e9ee1e9 100644 --- a/module/proof.go +++ b/module/proof.go @@ -169,3 +169,37 @@ func verifyAccount(target *types.Header, accountProof []byte, path common.Addres } return &account, nil } + +type getAccountProof = func(height int64) ([]byte, common.Hash, error) + +func withProofAndValidators(headerFn getHeaderFn, accountProofFn getAccountProof, height uint64, ethHeaders []*ETHHeader) (core.Header, error) { + + // get RLP-encoded account proof + rlpAccountProof, _, err := accountProofFn(int64(height)) + if err != nil { + return nil, fmt.Errorf("failed to get account proof : height = %d, %+v", height, err) + } + + header := &Header{ + AccountProof: rlpAccountProof, + Headers: ethHeaders, + } + + // Get validator set for verify headers + previousEpoch := getPreviousEpoch(height) + var previousTurnLength uint8 + header.PreviousValidators, previousTurnLength, err = queryValidatorSetAndTurnLength(headerFn, previousEpoch) + header.PreviousTurnLength = uint32(previousTurnLength) + if err != nil { + return nil, fmt.Errorf("ValidatorSet was not found in previous epoch : number = %d : %+v", previousEpoch, err) + } + currentEpoch := getCurrentEpoch(height) + var currentTurnLength uint8 + header.CurrentValidators, currentTurnLength, err = queryValidatorSetAndTurnLength(headerFn, currentEpoch) + header.CurrentTurnLength = uint32(currentTurnLength) + if err != nil { + return nil, fmt.Errorf("ValidatorSet was not found in current epoch : number= %d : %+v", currentEpoch, err) + } + + return header, nil +} diff --git a/module/prover.go b/module/prover.go index 8aa443d..290e41e 100644 --- a/module/prover.go +++ b/module/prover.go @@ -124,24 +124,12 @@ func (pr *Prover) SetupHeadersForUpdateByLatestHeight(clientStateLatestHeight ex } return pr.withProofAndValidators(height, ethHeaders) } - queryVerifiableNonNeighboringEpochHeader := func(height uint64, limitHeight uint64, checkpoint uint64) (core.Header, error) { - ethHeaders, err := queryFinalizedHeaderAfterCheckpoint(pr.chain.Header, height, limitHeight, checkpoint) - if err != nil { - return nil, err - } - // No finalized header found - if ethHeaders == nil { - return nil, nil - } - return pr.withProofAndValidators(height, ethHeaders) - } latestHeight, err := pr.chain.LatestHeight() if err != nil { return nil, err } return setupHeadersForUpdate( queryVerifiableNeighboringEpochHeader, - queryVerifiableNonNeighboringEpochHeader, pr.chain.Header, clientStateLatestHeight, latestFinalizedHeader, @@ -210,42 +198,18 @@ func (pr *Prover) CheckRefreshRequired(counterparty core.ChainInfoICS02Querier) } func (pr *Prover) withProofAndValidators(height uint64, ethHeaders []*ETHHeader) (core.Header, error) { - - // get RLP-encoded account proof - rlpAccountProof, _, err := pr.getAccountProof(int64(height)) - if err != nil { - return nil, fmt.Errorf("failed to get account proof : height = %d, %+v", height, err) - } - - header := &Header{ - AccountProof: rlpAccountProof, - Headers: ethHeaders, - } - - // Get validator set for verify headers - previousEpoch := getPreviousEpoch(height) - header.PreviousValidators, err = queryValidatorSet(pr.chain.Header, previousEpoch) - if err != nil { - return nil, fmt.Errorf("ValidatorSet was not found in previous epoch : number = %d : %+v", previousEpoch, err) - } - currentEpoch := getCurrentEpoch(height) - header.CurrentValidators, err = queryValidatorSet(pr.chain.Header, currentEpoch) - if err != nil { - return nil, fmt.Errorf("ValidatorSet was not found in current epoch : number= %d : %+v", currentEpoch, err) - } - - return header, nil + return withProofAndValidators(pr.chain.Header, pr.getAccountProof, height, ethHeaders) } func (pr *Prover) buildInitialState(dstHeader core.Header) (exported.ClientState, exported.ConsensusState, error) { currentEpoch := getCurrentEpoch(dstHeader.GetHeight().GetRevisionHeight()) - currentValidators, err := queryValidatorSet(pr.chain.Header, currentEpoch) + currentValidators, currentTurnLength, err := queryValidatorSetAndTurnLength(pr.chain.Header, currentEpoch) if err != nil { return nil, nil, err } previousEpoch := getPreviousEpoch(dstHeader.GetHeight().GetRevisionHeight()) - previousValidators, err := queryValidatorSet(pr.chain.Header, previousEpoch) + previousValidators, previousTurnLength, err := queryValidatorSetAndTurnLength(pr.chain.Header, previousEpoch) if err != nil { return nil, nil, err } @@ -277,9 +241,14 @@ func (pr *Prover) buildInitialState(dstHeader core.Header) (exported.ClientState } consensusState := ConsensusState{ Timestamp: header.Time, - PreviousValidatorsHash: crypto.Keccak256(previousValidators...), - CurrentValidatorsHash: crypto.Keccak256(currentValidators...), + PreviousValidatorsHash: makeEpochHash(previousValidators, previousTurnLength), + CurrentValidatorsHash: makeEpochHash(currentValidators, currentTurnLength), StateRoot: stateRoot.Bytes(), } return &clientState, &consensusState, nil } + +func makeEpochHash(validators Validators, turnLength uint8) []byte { + validatorsHash := crypto.Keccak256(validators...) + return crypto.Keccak256(append([]byte{turnLength}, validatorsHash...)) +} diff --git a/module/prover_test.go b/module/prover_test.go index 2287268..d161264 100644 --- a/module/prover_test.go +++ b/module/prover_test.go @@ -17,235 +17,17 @@ import ( "github.com/datachainlab/ethereum-ibc-relay-chain/pkg/client" "github.com/datachainlab/ethereum-ibc-relay-chain/pkg/relay/ethereum" "github.com/ethereum/go-ethereum/common" - types2 "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/rlp" "github.com/hyperledger-labs/yui-relayer/core" "github.com/stretchr/testify/suite" ) -const ( - hdwMnemonic = "math razor capable expose worth grape metal sunset metal sudden usage scheme" - hdwPath = "m/44'/60'/0'/0/0" - - // contract address changes for each deployment - ibcHandlerAddress = "aa43d337145e8930d01cb4e60abf6595c692921e" -) - type mockChain struct { Chain - chainLatestHeight uint64 - clientStateLatestHeight uint64 consensusStateTimestamp map[exported.Height]uint64 chainTimestamp map[exported.Height]uint64 - chainID uint64 -} - -func (c *mockChain) CanonicalChainID(ctx context.Context) (uint64, error) { - return c.chainID, nil -} - -func (c *mockChain) QueryClientState(ctx core.QueryContext) (*clienttypes.QueryClientStateResponse, error) { - cHeight := clienttypes.NewHeight(ctx.Height().GetRevisionNumber(), c.clientStateLatestHeight) - cs := ClientState{ - LatestHeight: &cHeight, - IbcStoreAddress: common.Hex2Bytes(ibcHandlerAddress), - } - anyClientState, err := codectypes.NewAnyWithValue(&cs) - if err != nil { - return nil, err - } - return clienttypes.NewQueryClientStateResponse(anyClientState, nil, cHeight), nil -} - -func (c *mockChain) QueryClientConsensusState(_ core.QueryContext, height exported.Height) (*clienttypes.QueryConsensusStateResponse, error) { - cHeight := clienttypes.NewHeight(height.GetRevisionNumber(), height.GetRevisionHeight()) - cs := ConsensusState{ - StateRoot: common.Hash{}.Bytes(), - Timestamp: c.consensusStateTimestamp[cHeight], - CurrentValidatorsHash: common.Hash{}.Bytes(), - PreviousValidatorsHash: common.Hash{}.Bytes(), - } - anyConsensusState, err := codectypes.NewAnyWithValue(&cs) - if err != nil { - return nil, err - } - return clienttypes.NewQueryConsensusStateResponse(anyConsensusState, nil, cHeight), nil -} - -func (c *mockChain) Header(_ context.Context, height uint64) (*types2.Header, error) { - headerMap := map[uint64]types2.Header{ - 31297221: { - ParentHash: common.HexToHash("da01d8fede81f2840ea4bd2d5586d4303f68c73becf0a23d1d6dddd4890bd274"), - UncleHash: common.HexToHash("1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"), - Coinbase: common.HexToAddress("ea0a6e3c511bbd10f4519ece37dc24887e11b55d"), - Root: common.HexToHash("97528e3167d013309f8585c8db78f4af02b0acbcf92e6b3aac530f9972b18ded"), - TxHash: common.HexToHash("ed65d042cdbf107e3803eb2aaa1932b1ae28ab8b2fc4df9bafb9217b390aa9c9"), - ReceiptHash: common.HexToHash("b8394040a65867ce80c2f4fd34d3bba3095b80ff9ccaea1e58669ca564a1e103"), - Bloom: types2.BytesToBloom(common.Hex2Bytes("91a876410d0c7012c91502d6845200a6d208a629cdcc06a0053861b2b9760ba2c8293640420712c5329374810216e098cfeba05d250267e0d8421025952c6a30242ee00309c60244e5338ccbca3104be2518206551e6580b0c5d81b0c8a33c05e02cb13e7b22c3cb248d041493691c51087c8acb1b0bb68e884ec552e443b4041e0b07914679c2eb02f4240458036fae4aa6fe9dd421313b75513b74aa505c30067648177ea9d9c2332d5deebe9f38d046eac9840301613312c0252a7813aaf8ee39440e3088e446cc5d0a9e1ca2fb00a0c8b1421d1dc03611ba406a2a34e5fd16399c1d89dec60741b05462e1110945781a845e7db1796c9bca3e909b61205d")), - Difficulty: big.NewInt(2), - Number: big.NewInt(31297221), - GasLimit: 0x8583b00, - GasUsed: 0xaa7b54, - Time: 0x64eee0d4, - Extra: common.Hex2Bytes("d88301020b846765746888676f312e31392e38856c696e7578000000b19df4a2f8b5830ddfffb860b4de956fe39e1e7e6b535f75054f2efea8ac185ac2b76384c749cc45f7decfea9999b9b3b41e5666e36408069cdd06870e266fe868b9128ce0a0aecf4ecc6b0e42d10c5e646e9571a862dee7112e88f39ddc476b67be9cf32ccb337d3496f901f84c8401dd8ec3a035be0876c21a5a5726193d1adb8ce9ebb6eb95757407cafb9106a57f0d3d12228401dd8ec4a0da01d8fede81f2840ea4bd2d5586d4303f68c73becf0a23d1d6dddd4890bd27480939d982a7958bf5912c1105da4673d035df33b685ad798e6f589ada1b40f63fa27edbbcea731e17928a54c07847a70d7e262a0bc41e68e5fcda124a37f4340b301"), - MixDigest: common.HexToHash("0000000000000000000000000000000000000000000000000000000000000000"), - Nonce: [8]byte{}, - BaseFee: big.NewInt(0), - }, - 31297220: { - ParentHash: common.HexToHash("35be0876c21a5a5726193d1adb8ce9ebb6eb95757407cafb9106a57f0d3d1222"), - UncleHash: common.HexToHash("1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"), - Coinbase: common.HexToAddress("d93dbfb27e027f5e9e6da52b9e1c413ce35adc11"), - Root: common.HexToHash("1283c0ddaf635ba45c04c7dcd3ee83370027d55fee45e9bd2a8f121074808ece"), - TxHash: common.HexToHash("62c9236c31a88ecf2d5ecb4666f06b78fad90bc6cde486714c92ac123b26e56b"), - ReceiptHash: common.HexToHash("babb28a01a3e0fe3657bd296123c54e8e6368588e943ab3b966d97effdcc1ae2"), - Bloom: types2.BytesToBloom(common.Hex2Bytes("dd6dd27f6ff5373d2ef7e4edba7714d6f3daf37bd7d8bfffba5fd73b32befff7ffc75fcbfbb955cfeab33ff77d1fd0b7fbd3d1fc05f5f02f7faf3efff3ed7afcffcffbf65d52ad3c9b75cedcb8d672fafdb1ffbf52f7af38e2fce0bffa6b0e3f5ffd7dfeaf4fcd630acd8ffc917b3dbf0ca36c63784d76b65eead7b9f6ef1fbf5aafff6e2e5fba9ff4ffbd57eeebdcbe76f67db77c36bdc86dabb3d3bccbdead97e726e3ebbefbf6effef7efcffebec3f7afcfef4ebaf9b5f7eaf77e6f5bebebe5e7f59ea35efbf7f6ea5d2fc36ffdeeadffb5eec3ba5e3dbbd774cef627f77ff1bafa3dbdf3d9de2735e7c685a723b6fc3e27fb767d7179bf2ffadfb9b9d8fb")), - Difficulty: big.NewInt(2), - Number: big.NewInt(31297220), - GasLimit: 0x85832a7, - GasUsed: 0x142a9ef, - Time: 0x64eee0d1, - Extra: common.Hex2Bytes("d88301020a846765746888676f312e32302e34856c696e7578000000b19df4a2f8b5830ddfffb860a4332ba47e6728f4b0e52e490cf4bd3cc4fc742c12bb8a8e5912095c71d9c845f5ddc5fdd4128dbed0e1bcaf4da8236b05ded0aa4a4c81f4a4fb2250f790fe1b21edb1aed0bc7bb7d4a78b26c6dd9af3b65a2bacb5b44e4a7b1dc3284e9d7d6bf84c8401dd8ec2a00f0fc4bae073bbeae37d8ff5395c95480fe5a9149bad4f0cd4f5e8e32d18b32e8401dd8ec3a035be0876c21a5a5726193d1adb8ce9ebb6eb95757407cafb9106a57f0d3d1222805bd7bc1a83768b5c7a505eed50eca8fdddd8a583a46d37f80a2d714be9f8ca2b04b0ba1398956512d18b30e3a56755245df898b98f8d5f6131eb7527f7dc65b101"), - MixDigest: common.HexToHash("0000000000000000000000000000000000000000000000000000000000000000"), - Nonce: [8]byte{}, - BaseFee: big.NewInt(0), - }, - 31297219: { - ParentHash: common.HexToHash("0f0fc4bae073bbeae37d8ff5395c95480fe5a9149bad4f0cd4f5e8e32d18b32e"), - UncleHash: common.HexToHash("1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"), - Coinbase: common.HexToAddress("d1d6bf74282782b0b3eb1413c901d6ecf02e8e28"), - Root: common.HexToHash("a6923c4f9bce5b7cc15a16d85222ce2618aa0f12bca0fa6b703d9aa5aa412648"), - TxHash: common.HexToHash("57dc9bdab942a85992bf2bb645594c35d9aa1df083fee8207df409886d313d6d"), - ReceiptHash: common.HexToHash("3bfa2879642e0273e765670993bff0ec2f22e589317782599cc6b79453441096"), - Bloom: types2.BytesToBloom(common.Hex2Bytes("eea73ff54e3fd7191d7f53f49ca3c29eb5b9688d0fafc2d33e7ee12d3a35cc69ef7ebd97cfc31b177a6b73ccda3622f8f9b6d95b59976d306e3ecc5f7431eed49e5cd9f70ff7cd29df7de1ebfd3bae347bbd98a770559ede746e6f93c9fb4e23eb3db0a53e57bf4eb77d7c36d3f37944cd99ddd55bb79f7e1d57f5b7ee1b6eeaf987c3a4da37134c5fa5be1fd2107bce442ea68f7c34fc9f6beba6df46fb78e63fd7323f57c723718edfddce9bd9fd425a978f65a7bed42fff41f666aefb58f76dd3ff561332ffaeb7fac28d55e99b7cf1f7b1a768b7a8bcc13e7ce715f4affed53eb4e4b1c177bd5f5d2de36bf39bd6b8d6976e5dec7cccb4f4fd932a677ecd")), - Difficulty: big.NewInt(2), - Number: big.NewInt(31297219), - GasLimit: 0x84fe2c6, - GasUsed: 0xf43a7c, - Time: 0x64eee0ce, - Extra: common.Hex2Bytes("d88301020a846765746888676f312e32302e35856c696e7578000000b19df4a2f8b58305dfffb860b7ab6f15df58e54befa47c75d64d32161823c59edf5bade334b55623eceb68b45752b058206ab7805f277362b7df153601ff6c28a4359f22a74b39304f929af5ca3192f58af57955bd33002402c6824834448ac33fb34d702d2e0d08d2bdcb8cf84c8401dd8ec1a0a493bd047c4c05912239fccde0dbd49730ec916afaabff66abd2e4d8bb351a938401dd8ec2a00f0fc4bae073bbeae37d8ff5395c95480fe5a9149bad4f0cd4f5e8e32d18b32e80515ed762f28c37e88f3d4f21bb33aa5fbd548f3bd168a4b4eeba9ed4c128f79f16886350f86283a571bd58d56cbe2ede5500d4261f8536677c4f24fd5542db0a00"), - MixDigest: common.HexToHash("0000000000000000000000000000000000000000000000000000000000000000"), - Nonce: [8]byte{}, - BaseFee: big.NewInt(0), - }, - 31297218: { - ParentHash: common.HexToHash("a493bd047c4c05912239fccde0dbd49730ec916afaabff66abd2e4d8bb351a93"), - UncleHash: common.HexToHash("1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"), - Coinbase: common.HexToAddress("cc8e6d00c17eb431350c6c50d8b8f05176b90b11"), - Root: common.HexToHash("b111fd4d787edd2a9a54e9e76aabac9bedf7213ddcf44b9960f334c9303b0256"), - TxHash: common.HexToHash("c81295cf7fdfa201ef13477519a25fd0749c8085acc05f59386291fb87fac10b"), - ReceiptHash: common.HexToHash("6024c6edc9ef851420121f565972736a182e40a2c5603c40de6afa8c1848b83b"), - Bloom: types2.BytesToBloom(common.Hex2Bytes("66a0839004a3501048881050821442000900040000814969480300289840012088035a00108000010a8810000142020081618811240001212020801000201a0404140848034000200106100898884434249023000244010020441200808006000a0b20201a0200182402005810002a401800c80c007e36260000401083c8041c0020c39684308058138424001c0010002824a40524a0100810081440184028a0a2d8180110814006022c40083b1001004000a010400200043001192823100044932045028012804600700820a92612402820010000040838011451d20800a4250838080102003100032184089002111440200b0426a050480010300000011001")), - Difficulty: big.NewInt(2), - Number: big.NewInt(31297218), - GasLimit: 0x8583b00, - GasUsed: 0x35a2f2, - Time: 0x64eee0cb, - Extra: common.Hex2Bytes("d98301020a846765746889676f312e31392e3131856c696e75780000b19df4a2f8b58305dfffb860afc7a23949201ffc50f92c39cb6a3a42f960edd1cafc424b852f511da8dbc052c0bb0222baa6b3a560cfe41a5a7b95c709c11e05b6471366ddb49ba73d0a547b085851d45b51dfbff2cc71f2ca93ff0d6402ecf1c534f240e4b67dfec13efc38f84c8401dd8ec0a03f20b11009e964211f4ef2e316ddf214066d6e0603b6fa2a283b14133c0aeb1b8401dd8ec1a0a493bd047c4c05912239fccde0dbd49730ec916afaabff66abd2e4d8bb351a9380740b7c6a2a1f2f5083f10dc247ed6e6223edd986368179556bd9dd3d78949149357dd8ed2793a0c701d6b7df744261439b71ef4cd2ef9b189afcc2f8105745ac01"), - MixDigest: common.HexToHash("0000000000000000000000000000000000000000000000000000000000000000"), - Nonce: [8]byte{}, - BaseFee: big.NewInt(0), - }, - 31297217: { - ParentHash: common.HexToHash("3f20b11009e964211f4ef2e316ddf214066d6e0603b6fa2a283b14133c0aeb1b"), - UncleHash: common.HexToHash("1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"), - Coinbase: common.HexToAddress("35ebb5849518aff370ca25e19e1072cc1a9fabca"), - Root: common.HexToHash("158af1b358e1ab7c08fd65a742d3e36c372859047aa6d1f8b47f8c6ca1a21d13"), - TxHash: common.HexToHash("2e308aa7adf3de39000a56dfd3596435e357304504b9ecb1401492dcc101cf88"), - ReceiptHash: common.HexToHash("698a86c1d0922df0705634891cbc82347d693ecd9e6ec0201ac9b9ffb4006cca"), - Bloom: types2.BytesToBloom(common.Hex2Bytes("14244b5f06401457d30562ee82512903900dd1291845c7203f3f49517c14a7b08eeb1643764ed0295a328daf585e442a87c0dc3eef1ab1195200248805275b88847ad90a0f564c1a133a621dd3ed006af41494d545467e5bb5bc80f9b4492d36ce2c12a7aa064353340d18a5c11659c04904a952bb45fd06a344ee50cb4db65090eaa19787bd929d10bf6608d508b19b24651ec5f916309b31b68cf88841c8becf098432529e06423a2e83edae3fb40226ea99652ac09398fa626db2f116c4c8a47057b20a81292e13d0ee6674a0d92221d50e6a8126ea1d835fdbdab2b8fc2e9cb0ced009a6e37d29d5a842f5018932486c87294162fae82017883c5e6960c4")), - Difficulty: big.NewInt(2), - Number: big.NewInt(31297217), - GasLimit: 0x8582a4f, - GasUsed: 0xd5aba3, - Time: 0x64eee0c8, - Extra: common.Hex2Bytes("d883010209846765746888676f312e32302e36856c696e7578000000b19df4a2f8b58305dfffb860887daa937dc51ef1bdc88a3f2e52f51ccc297a3439741cf23e3bc635ecca60413c070e136840b09112b15158b54887801215cd8e3354c552e03587b922c8aa3c444c55336eaefafbf88708863869316136f0a68e45d62c243eb5976dffe41656f84c8401dd8ebfa0d1cbcb756aa78425abb3fd8eb10e814c67b8cf6e7750458b8c597388bd8682928401dd8ec0a03f20b11009e964211f4ef2e316ddf214066d6e0603b6fa2a283b14133c0aeb1b80b2c9b0fdb99e7bf632bdb2ab30550cff337b15c9163fddc47c9cc20b9582c71343857e79a7dae2b38715d8cbecf111a2d1cfcfbad8f4b65abd6b67ad2eb97bb900"), - MixDigest: common.HexToHash("0000000000000000000000000000000000000000000000000000000000000000"), - Nonce: [8]byte{}, - BaseFee: big.NewInt(0), - }, - 31297216: { - ParentHash: common.HexToHash("d1cbcb756aa78425abb3fd8eb10e814c67b8cf6e7750458b8c597388bd868292"), - UncleHash: common.HexToHash("1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"), - Coinbase: common.HexToAddress("b4dd66d7c2c7e57f628210187192fb89d4b99dd4"), - Root: common.HexToHash("57ede97b62b05af1187766de108267b2f27537ed9edd1a9f7889529db4cca965"), - TxHash: common.HexToHash("93775f7dad7f0678386501fd9419fbff9e902707687c7baa4c73478a74c4e839"), - ReceiptHash: common.HexToHash("0e3fb454aa5489134df6457875bfde27c8eb43f092cf84cffb1f007d8acbe1fe"), - Bloom: types2.BytesToBloom(common.Hex2Bytes("882cc625e0381010c60011c584004440a00b1121012c82100038612a16088082af04b07e28049011662125b1020680b08300148849480620d8262c280a640a081d7485d2514625203328e09802204128703622a52054820e002d0000c8148445c20908222a1605012229022681101ae2081010175041848624510818de623640110a2901466d5882229d258e1921042a8924158511203a8800c8c0508980102092050022078d1402270638cd3f0a1640cc058d0108128189308365a020c224d8242c1ce290c361864190899b1a0012542500061006104094031347462a02e424281808521004114021881c484c0041295950e26951e09448a002419000413b06")), - Difficulty: big.NewInt(2), - Number: big.NewInt(31297216), - GasLimit: 0x84fda76, - GasUsed: 0x847ded, - Time: 0x64eee0c4, - Extra: common.Hex2Bytes("d98301020a846765746889676f312e31392e3131856c696e75780000b19df4a2f8b5830ddfffb860b01dbdb421b9fb5b1f71f196b5e1a8979b353ebfb25bf1a0ef31cc692139df7918b4d2db38211f91ee023bbdf78ac50b00d1497f7d90e42adb7826b21c129d5c706219f37d9216b27be379a4f2854149fa744ef734e8558070c5e8c4fd794c5df84c8401dd8ebea017148d821da270f09540075131924b934bc0352dd71d8b8f60274f39d73231dd8401dd8ebfa0d1cbcb756aa78425abb3fd8eb10e814c67b8cf6e7750458b8c597388bd868292808cc4af67170aaa12f7d2c44f6bec754eadaad71cf12df86ad87667fb2a9579940c3a579e4b5bb1c63c02b488429d683c9e3599b0583f0e4015e98d674f58281f00"), - MixDigest: common.HexToHash("0000000000000000000000000000000000000000000000000000000000000000"), - Nonce: [8]byte{}, - BaseFee: big.NewInt(0), - }, - 31297215: { - ParentHash: common.HexToHash("17148d821da270f09540075131924b934bc0352dd71d8b8f60274f39d73231dd"), - UncleHash: common.HexToHash("1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"), - Coinbase: common.HexToAddress("b218c5d6af1f979ac42bc68d98a5a0d796c6ab01"), - Root: common.HexToHash("a6e3d060b775a05eaa251583fb248df682fa839bd575d254eb4330d6c92f0356"), - TxHash: common.HexToHash("4a81457bed752a8611a3fcf1409e6bfc34c8006651f64e6fdb5530a113d8972c"), - ReceiptHash: common.HexToHash("a8539e4e87b5ce8ee15a3f9c52113062de8883c1ea062255959e3f3f5350ec00"), - Bloom: types2.BytesToBloom(common.Hex2Bytes("1177e6c48819553fcb1800dcc612126e24206a13cd4d054bea0a07b81f00a03e8e43f8c2c280905102227a9355da28c18e1c000a071c61a140352328113d228007d640114bd00c69db01a449c835706ca8dcab8040744802234e841088042eb42a9d23365e262a370c0d001693eafc4348a6a440294fdf23010ac910944b6df8888ec3142b5440dc30aa5500a894fc9bf0b646857e6838de318cd1c300929c20828da412533ae674b610cb1e6f85e54008a4d7d0878286a57469a3b57752a2e7b38f14828276a80e30ab1c48f23650e0b41447e5c14f0417819e7d87833cefab519990032ef8e7274125026a8163152c278085a9d078c67c23b87d00da15f00b")), - Difficulty: big.NewInt(2), - Number: big.NewInt(31297215), - GasLimit: 0x84792e5, - GasUsed: 0xaac551, - Time: 0x64eee0c1, - Extra: common.Hex2Bytes("d88301020a846765746888676f312e32302e35856c696e7578000000b19df4a2f8b5830ddfffb860b9b1a84b0ce0243a5b8592ffc6562f1f9f6e95197a1ca1ea17eb300b4f101382aff91466a179e5b9ad4fa3423f6ed40f14edef5a8addd5590754049e9828001b3aa9e355abd098b01b059781512654f9dce636865e6dd98c9c41066e09f64af2f84c8401dd8ebda0e5ec815463a14fc0a652302d302e93c2a06280d115782a183f5378692e8638288401dd8ebea017148d821da270f09540075131924b934bc0352dd71d8b8f60274f39d73231dd80615eb294cc6f3c9f5a307dca23199a3844bf63b9078c41d457d7732a7956189a4b68c910d5ed0eb7fe4e7432061ab9ca6bccc150099a5ad554112aa34494cc6801"), - MixDigest: common.HexToHash("0000000000000000000000000000000000000000000000000000000000000000"), - Nonce: [8]byte{}, - BaseFee: big.NewInt(0), - }, - 31297200: { - ParentHash: common.HexToHash("10c8358490a494a40c5c92aff8628fa770860a9d34e7fb7df38dfb208b0ddfc3"), - UncleHash: common.HexToHash("1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"), - Coinbase: common.HexToAddress("e9ae3261a475a27bb1028f140bc2a7c843318afd"), - Root: common.HexToHash("111504390f79560bc7fa5d1d5b8cdb109d0ee1aa76816dba43b88f1e5e152b6f"), - TxHash: common.HexToHash("2a2eb4b95af5c879078702bfccd6147bd47162385898d8c0b81fb94ac5456a60"), - ReceiptHash: common.HexToHash("57ed46152fe61b432e682da7f0b82273e1fee09674b2b62c64952e214e84e7e1"), - Bloom: types2.BytesToBloom(common.Hex2Bytes("8035164600431418e05400edd0a9650e8238c2833980eadd35538b33d3641594dc00b06042041004a398b01d821aa232cdb11211a044e339d0440056482c6ec80e61d00aa544881a8b61c2988220042db254432900c6c8410045114b80ba0021cd6c20a23a66042b04e7971817460d6c0e52e95a00cbd4809580a4d9804e35c6998a0246256d4ad18588363010a0d89030240cc77a03158a0f4d83c0ac841cb0871050c8f73f6650e6153206369a061a0c2d90835480d12374a021a1605a2278e3209746a6555c4a32a1b8b87a629968238cf242a088ac190b51fa72f200e56c579880051b2042824b1db2e7058003c1619cfc307864e1c8fc2a690299a1864a")), - Difficulty: big.NewInt(2), - Number: big.NewInt(31297200), - GasLimit: 0x8583b00, - GasUsed: 0xa136cd, - Time: 0x64eee094, - Extra: common.Hex2Bytes("d88301020a846765746888676f312e32302e35856c696e7578000000b19df4a2150bac492386862ad3df4b666bc096b0505bb694dab0bec348681af766751cb839576e9c515a09c8bffa30a46296ccc56612490eb480d03bf948e10005bbcc0421f90b3d4e2465176c461afb316ebc773c61faee85a6515daa8a923564c6ffd37fb2fe9f118ef88092e8762c7addb526ab7eb1e772baef85181f892c731be0c1891a50e6b06262c816295e26495cef6f69dfa69911d9d8e4f3bbadb89b977cf58294f7239d515e15b24cfeb82494056cf691eaf729b165f32c9757c429dba5051155903067e56ebe3698678e9135ebb5849518aff370ca25e19e1072cc1a9fabcaa7f3e2c0b4b16ad183c473bafe30a36e39fa4a143657e229cd23c77f8fbc8e4e4e241695dd3d248d1e51521eee6619143f349bbafec1551819b8be1efea2fc46ca749aa184248a459464eec1a21e7fc7b71a053d9644e9bb8da4853b8f872cd7c1d6b324bf1922829830646ceadfb658d3de009a61dd481a114a2e761c554b641742c973867899d38a80967d39e406a0a9642d41e9007a27fc1150a267d143a9f786cd2b5eecbdcc4036273705225b956d5e2f8f5eb95d2569c77a677c40c7fbea129d4b171a39b7a8ddabfab2317f59d86abfaf690850223d90e9e7593d91a29331dfc2f84d5adecc75fc39ecab4632c1b4400a3dd1e1298835bcca70f657164e5b75689b64b7fd1fa275f334f28e1896a26afa1295da81418593bd12814463d9f6e45c36a0e47eb4cd3e5b6af29c41e2a3a5636430155a466e216585af3ba772b61c6014342d914470ec7ac2975be345796c2b81db0422a5fd08e40db1fc2368d2245e4b18b1d0b85c921aaaafd2e341760e29fc613edd39f71254614e2055c3287a517ae2f5b9e386cd1b50a4550696d957cb4900f03ab84f83ff2df44193496793b847f64e9d6db1b3953682bb95edd096eb1e69bbd357c200992ca78050d0cbe180cfaa018e8b6c8fd93d6f4cea42bbb345dbc6f0dfdb5bec73a8a257074e82b881cfa06ef3eb4efeca060c2531359abd0eab8af1e3edfa2025fca464ac9c3fd123f6c24a0d78869485a6f79b60359f141df90a0c745125b131caaffd12b772e180fbf38a051c97dabc8aaa0126a233a9e828cdafcc7422c4bb1f4030a56ba364c54103f26bad91508b5220b741b218c5d6af1f979ac42bc68d98a5a0d796c6ab01b659ad0fbd9f515893fdd740b29ba0772dbde9b4635921dd91bd2963a0fc855e31f6338f45b211c4e9dedb7f2eb09de7b4dd66d7c2c7e57f628210187192fb89d4b99dd4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000be807dddb074639cd9fa61b47676c064fc50d62cb1f2c71577def3144fabeb75a8a1c8cb5b51d1d1b4a05eec67988b8685008baa17459ec425dbaebc852f496dc92196cdcc8e6d00c17eb431350c6c50d8b8f05176b90b11b3a3d4feb825ae9702711566df5dbf38e82add4dd1b573b95d2466fa6501ccb81e9d26a352b96150ccbf7b697fd0a419d1d6bf74282782b0b3eb1413c901d6ecf02e8e28939e8fb41b682372335be8070199ad3e8621d1743bcac4cc9d8f0f6e10f41e56461385c8eb5daac804fe3f2bca6ce739d93dbfb27e027f5e9e6da52b9e1c413ce35adc11000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ea0a6e3c511bbd10f4519ece37dc24887e11b55db2d4c6283c44a1c7bd503aaba7666e9f0c830e0ff016c1c750a5e48757a713d0836b1cabfd5c281b1de3b77d1c192183ee226379db83cffc681495730c11fdde79ba4c0cae7bc6faa3f0cc3e6093b633fd7ee4f86970926958d0b7ec80437f936acf212b78f0cd095f4565fff144fd458d233a5bef0274e31810c9df02f98fafde0f841f4e66a1cd000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f8b5830aefffb86097bc63a64e8d730014c39dcaac8f3309e37a11c06f0f5c233b55ba19c1f6c34d2d08de4b030ce825bb21fd884bc0fcb811336857419f5ca42a92ac149a4661a248de10f4ca6496069fdfd10d43bc74ccb81806b6ecd384617d1006b16dead7e4f84c8401dd8eaea0e61c6075d2ab24fcdc423764c21771cac6b241cbff89718f9cc8fc6459b4e7578401dd8eafa010c8358490a494a40c5c92aff8628fa770860a9d34e7fb7df38dfb208b0ddfc380ff15abfc44495e4d4605458bb485f0cac5a152b380a8d0208b3f9ff6216230ec4dd67a73b72b1d17a888c68e111f806ef0b255d012b5185b7420b5fb529c9b9300"), - MixDigest: common.HexToHash("0000000000000000000000000000000000000000000000000000000000000000"), - Nonce: [8]byte{}, - BaseFee: big.NewInt(0), - }, - 31297000: { - ParentHash: common.HexToHash("a0dcc3ef1e710117565d6cef7043f133595a6f1f57d9b49ded7e1a6bfb72659f"), - UncleHash: common.HexToHash("1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"), - Coinbase: common.HexToAddress("7ae2f5b9e386cd1b50a4550696d957cb4900f03a"), - Root: common.HexToHash("e1772b39389c0b57e2a0913139235645fdcc84efd902ca5f04bf0fbd6743359b"), - TxHash: common.HexToHash("ea03b553afbb8246c565183867eda57cc6a61cbd92064943462a04ba48122f1f"), - ReceiptHash: common.HexToHash("bd65f987e07936f6c672a1a4696f95777ed53e24cb0998e9e7f0753fb23adcc9"), - Bloom: types2.BytesToBloom(common.Hex2Bytes("00684a0053503034e8cc814484010402e200d85414009228001021810328923097109fe8460030048066d40814560200c930ca1082b86800655a8450002812210446842123e82900033012a842c08c2930d0092109604f0c060c1241802504c4042c0b607b2e08601204120013040a28384200d2006194a32c21381247430486102a210549594a842689948804b93588112e04852910908805d400c10081742023030c08d2a2021800080e17078e404848000cba05c2940208402479491360aa69e5d6020187480f90408900510098222201a20000586835a7d8d3323308a1c91c10a0020046a3b20b112445050057110b06840001a086ca2821b20098010018")), - Difficulty: big.NewInt(2), - Number: big.NewInt(31297000), - GasLimit: 0x85832a7, - GasUsed: 0x6c005b, - Time: 0x64eede3a, - Extra: common.Hex2Bytes("d88301020b846765746888676f312e31392e38856c696e7578000000b19df4a2150bac492386862ad3df4b666bc096b0505bb694dab0bec348681af766751cb839576e9c515a09c8bffa30a46296ccc56612490eb480d03bf948e10005bbcc0421f90b3d4e295e26495cef6f69dfa69911d9d8e4f3bbadb89b977cf58294f7239d515e15b24cfeb82494056cf691eaf729b165f32c9757c429dba5051155903067e56ebe3698678e912d4c407bbe49438ed859fe965b140dcf1aab71a993c1f7f6929d1fe2a17b4e14614ef9fc5bdc713d6631d675403fbeefac55611bf612700b1b65f4744861b80b0f7d6ab03f349bbafec1551819b8be1efea2fc46ca749aa184248a459464eec1a21e7fc7b71a053d9644e9bb8da4853b8f872cd7c1d6b324bf1922829830646ceadfb658d3de009a61dd481a114a2e761c554b641742c973867899d38a80967d39e406a0a9642d41e9007a27fc1150a267d143a9f786cd2b5eecbdcc4036273705225b956d5e2f8f5eb95d2570f657164e5b75689b64b7fd1fa275f334f28e1896a26afa1295da81418593bd12814463d9f6e45c36a0e47eb4cd3e5b6af29c41e2a3a5636430155a466e216585af3ba772b61c6014342d914470ec7ac2975be345796c2b81db0422a5fd08e40db1fc2368d2245e4b18b1d0b85c921aaaafd2e341760e29fc613edd39f71254614e2055c3287a517ae2f5b9e386cd1b50a4550696d957cb4900f03ab84f83ff2df44193496793b847f64e9d6db1b3953682bb95edd096eb1e69bbd357c200992ca78050d0cbe180cfaa018e8b6c8fd93d6f4cea42bbb345dbc6f0dfdb5bec73a8a257074e82b881cfa06ef3eb4efeca060c2531359abd0eab8af1e3edfa2025fca464ac9c3fd123f6c24a0d788694859f8ccdafcc39f3c7d6ebf637c9151673cbc36b888819ec5ec3e97e1f03bbb4bb6055c7a5feac8f4f259df58349a32bb5cb377e2cb1f362b77f1dd398cfd3e9dba46138c3a6f79b60359f141df90a0c745125b131caaffd12b772e180fbf38a051c97dabc8aaa0126a233a9e828cdafcc7422c4bb1f4030a56ba364c54103f26bad91508b5220b741b218c5d6af1f979ac42bc68d98a5a0d796c6ab01b659ad0fbd9f515893fdd740b29ba0772dbde9b4635921dd91bd2963a0fc855e31f6338f45b211c4e9dedb7f2eb09de7b4dd66d7c2c7e57f628210187192fb89d4b99dd4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cc8e6d00c17eb431350c6c50d8b8f05176b90b11b3a3d4feb825ae9702711566df5dbf38e82add4dd1b573b95d2466fa6501ccb81e9d26a352b96150ccbf7b697fd0a419ce2fd7544e0b2cc94692d4a704debef7bcb61328b64abe25614c9cfd32e456b4d521f29c8357f4af4606978296c9be93494072ac05fa86e3d27cc8d66e65000f8ba33fbbd1d6bf74282782b0b3eb1413c901d6ecf02e8e28939e8fb41b682372335be8070199ad3e8621d1743bcac4cc9d8f0f6e10f41e56461385c8eb5daac804fe3f2bca6ce739d93dbfb27e027f5e9e6da52b9e1c413ce35adc11000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e2d3a739effcd3a99387d015e260eefac72ebea1956c470ddff48cb49300200b5f83497f3a3ccb3aeb83c5edd9818569038e61d197184f4aa6939ea5e9911e3e98ac6d21e9ae3261a475a27bb1028f140bc2a7c843318afd000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ea0a6e3c511bbd10f4519ece37dc24887e11b55db2d4c6283c44a1c7bd503aaba7666e9f0c830e0ff016c1c750a5e48757a713d0836b1cabfd5c281b1de3b77d1c192183ef0274e31810c9df02f98fafde0f841f4e66a1cd000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f8b58305efffb8608605e361feaf30688803514a7f9071e61d3c992661f0f80671c72c571dccb7a3246759b622c815cd0fb166418e4e3ffe0a580db63d13c177927edebe460a7fd0ee1df6fc5e44f85c23f8fb01d413da8ced2c01e12e5c750dede91e845889837af84c8401dd8de6a01152160e4ada894f35233d509c56afb367fc0e43b7f5b4c4548d74bd48a519648401dd8de7a0a0dcc3ef1e710117565d6cef7043f133595a6f1f57d9b49ded7e1a6bfb72659f80ec5abb982536097426af57180bec01ec157d60c0e1c227d7b5f96c5e218c055834f7c5464206a5e49c638a1490ca924c38a6923909dccc9baae17f7a7d8011ee00"), - MixDigest: common.HexToHash("0000000000000000000000000000000000000000000000000000000000000000"), - Nonce: [8]byte{}, - BaseFee: big.NewInt(0), - }, - } - if v, ok := headerMap[height]; ok { - return &v, nil - } - - return &types2.Header{ - Root: common.HexToHash("c84307dfe4ccfec4a851a77755d63228d8e0b9ba3345d1eee37ed729ee16eaa1"), - Number: big.NewInt(int64(height)), - }, nil + latestHeight uint64 + trustedHeight uint64 } func (c *mockChain) GetProof(_ common.Address, _ [][]byte, _ *big.Int) (*client.StateProof, error) { @@ -271,16 +53,36 @@ func (c *mockChain) GetProof(_ common.Address, _ [][]byte, _ *big.Int) (*client. }, nil } -func (c *mockChain) LatestHeight() (exported.Height, error) { - return clienttypes.NewHeight(0, c.chainLatestHeight), nil +func (c *mockChain) QueryClientState(ctx core.QueryContext) (*clienttypes.QueryClientStateResponse, error) { + cHeight := clienttypes.NewHeight(ctx.Height().GetRevisionNumber(), c.trustedHeight) + cs := ClientState{ + LatestHeight: &cHeight, + } + anyClientState, err := codectypes.NewAnyWithValue(&cs) + if err != nil { + return nil, err + } + return clienttypes.NewQueryClientStateResponse(anyClientState, nil, cHeight), nil +} + +func (c *mockChain) QueryClientConsensusState(_ core.QueryContext, height exported.Height) (*clienttypes.QueryConsensusStateResponse, error) { + cHeight := clienttypes.NewHeight(height.GetRevisionNumber(), height.GetRevisionHeight()) + cs := ConsensusState{ + Timestamp: c.consensusStateTimestamp[cHeight], + } + anyConsensusState, err := codectypes.NewAnyWithValue(&cs) + if err != nil { + return nil, err + } + return clienttypes.NewQueryConsensusStateResponse(anyConsensusState, nil, cHeight), nil } func (c *mockChain) Timestamp(height exported.Height) (time.Time, error) { return time.Unix(int64(c.chainTimestamp[height]), 0), nil } -func (c *mockChain) GetLatestFinalizedHeader() (latestFinalizedHeader core.Header, err error) { - panic("never call") +func (c *mockChain) LatestHeight() (exported.Height, error) { + return clienttypes.NewHeight(0, c.latestHeight), nil } type ProverTestSuite struct { @@ -295,14 +97,14 @@ func TestProverTestSuite(t *testing.T) { func (ts *ProverTestSuite) SetupTest() { signerConfig := &hd.SignerConfig{ - Mnemonic: hdwMnemonic, - Path: hdwPath, + Mnemonic: "math razor capable expose worth grape metal sunset metal sudden usage scheme", + Path: "m/44'/60'/0'/0/0", } anySignerConfig, err := codectypes.NewAnyWithValue(signerConfig) ts.Require().NoError(err) chain, err := ethereum.NewChain(ethereum.ChainConfig{ EthChainId: 9999, - IbcAddress: ibcHandlerAddress, + IbcAddress: common.Address{}.String(), Signer: anySignerConfig, }) ts.Require().NoError(err) @@ -333,111 +135,22 @@ func (ts *ProverTestSuite) SetupTest() { } ts.chain = &mockChain{ Chain: NewChain(chain), - chainLatestHeight: 31297221, - clientStateLatestHeight: 31297000, - chainID: 9999, consensusStateTimestamp: make(map[exported.Height]uint64), chainTimestamp: make(map[exported.Height]uint64), + latestHeight: 0, + trustedHeight: 0, } ts.prover = NewProver(ts.chain, &config).(*Prover) } -func (ts *ProverTestSuite) TestQueryLatestFinalizedHeader() { - header, err := ts.prover.GetLatestFinalizedHeader() - ts.Require().NoError(err) - ts.Require().NoError(header.ValidateBasic()) - ts.Require().Len(header.(*Header).Headers, 3) - h := header.(*Header) - target, err := h.Target() - ts.Require().NoError(err) - ts.Require().Equal(target.Number.Int64(), int64(31297219)) - ts.Require().Len(h.PreviousValidators, 21) - ts.Require().Len(h.CurrentValidators, 21) - ts.Require().NotEqual(common.BytesToHash(crypto.Keccak256(h.CurrentValidators...)), common.BytesToHash(crypto.Keccak256(h.PreviousValidators...))) -} - -func (ts *ProverTestSuite) TestSetupHeadersForUpdate() { - type dstMock struct { - Chain - core.Prover - } - dst := dstMock{ - Chain: ts.prover.chain, - Prover: ts.prover, - } - - header, err := ts.prover.GetLatestFinalizedHeaderByLatestHeight(ts.chain.chainLatestHeight) - ts.Require().NoError(err) - setupDone, err := ts.prover.SetupHeadersForUpdate(dst.Chain.(*mockChain), header) - ts.Require().NoError(err) - ts.Require().Len(setupDone, 2) - first := setupDone[0].(*Header) - ts.Require().Len(first.Headers, 17) // Vote is not present in 14blocks(31297201~31297214) - ts.Require().Equal(int(first.GetHeight().GetRevisionHeight()), 31297200) - second := setupDone[1].(*Header) - ts.Require().Len(second.Headers, 3) - ts.Require().Equal(int(second.GetHeight().GetRevisionHeight()), 31297219) -} - -func (ts *ProverTestSuite) TestSuccessCreateInitialLightClientState() { - - heights := []exported.Height{nil, clienttypes.NewHeight(0, 31297219)} - - for _, height := range heights { - var err error - var finalizedHeader core.Header - if height == nil { - finalizedHeader, err = ts.prover.GetLatestFinalizedHeader() - } else { - finalizedHeader, err = ts.prover.GetLatestFinalizedHeaderByLatestHeight(height.GetRevisionHeight() + 2) - } - ts.Require().NoError(err) - target, err := finalizedHeader.(*Header).Target() - ts.Require().NoError(err) - stateRoot, err := ts.prover.GetStorageRoot(target) - ts.Require().NoError(err) - previousEpoch := GetPreviousEpoch(finalizedHeader.GetHeight().GetRevisionHeight()) - previousValidatorSet, err := QueryValidatorSet(ts.prover.chain.Header, previousEpoch) - ts.Require().NoError(err) - currentEpoch := GetCurrentEpoch(finalizedHeader.GetHeight().GetRevisionHeight()) - currentValidatorSet, err := QueryValidatorSet(ts.prover.chain.Header, currentEpoch) - ts.Require().NoError(err) - - s1, s2, err := ts.prover.CreateInitialLightClientState(height) - ts.Require().NoError(err) - cs := s1.(*ClientState) - ts.Require().Equal(cs.ChainId, uint64(9999)) - ts.Require().Equal(cs.TrustingPeriod, 100*time.Second) - ts.Require().Equal(cs.MaxClockDrift, 1*time.Millisecond) - ts.Require().False(cs.Frozen) - ts.Require().Equal(common.Bytes2Hex(cs.IbcStoreAddress), ibcHandlerAddress) - var commitment [32]byte - ts.Require().Equal(common.Bytes2Hex(cs.IbcCommitmentsSlot), common.Bytes2Hex(commitment[:])) - ts.Require().Equal(cs.GetLatestHeight(), finalizedHeader.GetHeight()) - - consState := s2.(*ConsensusState) - ts.Require().Equal(consState.CurrentValidatorsHash, crypto.Keccak256(currentValidatorSet...)) - ts.Require().Equal(consState.PreviousValidatorsHash, crypto.Keccak256(previousValidatorSet...)) - ts.Require().Equal(consState.Timestamp, target.Time) - ts.Require().Equal(common.BytesToHash(consState.StateRoot), stateRoot) - } -} - -func (ts *ProverTestSuite) TestErrorCreateInitialLightClientState() { - // No finalized header found - _, _, err := ts.prover.CreateInitialLightClientState(clienttypes.NewHeight(0, 31297220)) - ts.Require().Equal(err.Error(), "no finalized headers were found up to 31297221") -} - func (ts *ProverTestSuite) TestQueryClientStateWithProof() { - saved := ts.chain.clientStateLatestHeight - defer func() { - ts.chain.clientStateLatestHeight = saved - }() - ts.chain.clientStateLatestHeight = 21400 - - cs, err := ts.prover.chain.QueryClientState(core.NewQueryContext(context.TODO(), clienttypes.NewHeight(0, 0))) + cHeight := clienttypes.NewHeight(0, 21400) + anyClientState, err := codectypes.NewAnyWithValue(&ClientState{ + LatestHeight: &cHeight, + IbcStoreAddress: ts.prover.chain.IBCAddress().Bytes(), + }) ts.Require().NoError(err) + cs := clienttypes.NewQueryClientStateResponse(anyClientState, nil, cHeight) bzCs, err := ts.prover.chain.Codec().Marshal(cs) ts.Require().NoError(err) @@ -525,11 +238,10 @@ func (ts *ProverTestSuite) TestCheckRefreshRequired() { Prover: ts.prover, } now := time.Now() - chainHeight := clienttypes.NewHeight(0, ts.chain.chainLatestHeight) + chainHeight := clienttypes.NewHeight(0, 0) + csHeight := clienttypes.NewHeight(0, 0) ts.chain.chainTimestamp[chainHeight] = uint64(now.Unix()) - csHeight := clienttypes.NewHeight(0, ts.chain.clientStateLatestHeight) - // should refresh ts.chain.consensusStateTimestamp[csHeight] = uint64(now.Add(-51 * time.Second).Unix()) required, err := ts.prover.CheckRefreshRequired(dst) diff --git a/module/setup.go b/module/setup.go index acdb3cb..90e3dd1 100644 --- a/module/setup.go +++ b/module/setup.go @@ -10,11 +10,9 @@ import ( ) type queryVerifiableNeighboringEpochHeaderFn = func(uint64, uint64) (core.Header, error) -type queryVerifiableNonNeighboringEpochHeaderFn = func(uint64, uint64, uint64) (core.Header, error) func setupHeadersForUpdate( queryVerifiableNeighboringEpochHeader queryVerifiableNeighboringEpochHeaderFn, - queryVerifiableNonNeighboringEpochHeader queryVerifiableNonNeighboringEpochHeaderFn, getHeader getHeaderFn, clientStateLatestHeight exported.Height, latestFinalizedHeader *Header, @@ -34,51 +32,20 @@ func setupHeadersForUpdate( } trustedEpochHeight := toEpoch(savedLatestHeight) - lastUnsavedEpoch := toEpoch(latestFinalizedHeight) - // Check if last epoch can be directly verified by trusted height to reduce request for LCP - if lastUnsavedEpoch > trustedEpochHeight+constant.BlocksPerEpoch { - lastVerifiableEpoch, _ := setupNonNeighboringEpochHeader(getHeader, queryVerifiableNonNeighboringEpochHeader, lastUnsavedEpoch, trustedEpochHeight, latestHeight) - if lastVerifiableEpoch != nil { - log.GetLogger().Debug("Use direct non-neighboring epoch verification", "trusted", trustedEpochHeight, "latestFinalized", latestFinalizedHeight) - if lastUnsavedEpoch == latestFinalizedHeight { - return withTrustedHeight(append(targetHeaders, lastVerifiableEpoch), clientStateLatestHeight), nil - } else { - return withTrustedHeight(append(targetHeaders, lastVerifiableEpoch, latestFinalizedHeader), clientStateLatestHeight), nil - } - } - } // Append insufficient epoch blocks - for epochHeight := firstUnsavedEpoch; epochHeight <= latestFinalizedHeight; epochHeight += constant.BlocksPerEpoch { - if epochHeight == trustedEpochHeight+constant.BlocksPerEpoch { - verifiableEpoch, err := setupNeighboringEpochHeader(getHeader, queryVerifiableNeighboringEpochHeader, epochHeight, trustedEpochHeight, latestHeight) - if err != nil { - return nil, err - } - if verifiableEpoch == nil { - // not found -> non-neighboring epoch - continue - } - targetHeaders = append(targetHeaders, verifiableEpoch) - } else { - verifiableEpoch, err := setupNonNeighboringEpochHeader(getHeader, queryVerifiableNonNeighboringEpochHeader, epochHeight, trustedEpochHeight, latestHeight) - if err != nil { - return nil, err - } - if verifiableEpoch == nil { - // not found -> next non-neighboring epoch - continue - } - targetHeaders = append(targetHeaders, verifiableEpoch) + for epochHeight := firstUnsavedEpoch; epochHeight < latestFinalizedHeight; epochHeight += constant.BlocksPerEpoch { + verifiableEpoch, err := setupNeighboringEpochHeader(getHeader, queryVerifiableNeighboringEpochHeader, epochHeight, trustedEpochHeight, latestHeight) + if err != nil { + return nil, err } + if verifiableEpoch == nil { + log.GetLogger().Error("[FastFinalityError]", fmt.Errorf("insufficient vote attestation: epochHeight=%d, trustedEpochHeight=%d", epochHeight, trustedEpochHeight)) + return withTrustedHeight(targetHeaders, clientStateLatestHeight), nil + } + targetHeaders = append(targetHeaders, verifiableEpoch) trustedEpochHeight = epochHeight } - - if isEpoch(latestFinalizedHeight) || - // ex) trusted = 200, latest 401, not append latest because it can not be verified - trustedEpochHeight < toEpoch(latestFinalizedHeight) { - return withTrustedHeight(targetHeaders, clientStateLatestHeight), nil - } return withTrustedHeight(append(targetHeaders, latestFinalizedHeader), clientStateLatestHeight), nil } @@ -90,70 +57,27 @@ func setupNeighboringEpochHeader( latestHeight exported.Height, ) (core.Header, error) { // neighboring epoch needs block before checkpoint - currentValidatorSet, err := queryValidatorSet(getHeader, epochHeight) + currentValidatorSet, currentTurnLength, err := queryValidatorSetAndTurnLength(getHeader, epochHeight) if err != nil { return nil, fmt.Errorf("setupNeighboringEpochHeader: failed to get current validator set: epochHeight=%d : %+v", epochHeight, err) } - trustedValidatorSet, err := queryValidatorSet(getHeader, trustedEpochHeight) + trustedValidatorSet, trustedTurnLength, err := queryValidatorSetAndTurnLength(getHeader, trustedEpochHeight) if err != nil { return nil, fmt.Errorf("setupNeighboringEpochHeader: failed to get trusted validator set: trustedEpochHeight=%d : %+v", trustedEpochHeight, err) } if trustedValidatorSet.Contains(currentValidatorSet) { // ex) trusted(prevSaved = 200), epochHeight = 400 must be finalized by min(610,latest) - nextCheckpoint := currentValidatorSet.Checkpoint(epochHeight + constant.BlocksPerEpoch) + nextCheckpoint := currentValidatorSet.Checkpoint(currentTurnLength) + (epochHeight + constant.BlocksPerEpoch) limit := minUint64(nextCheckpoint-1, latestHeight.GetRevisionHeight()) return queryVerifiableHeader(epochHeight, limit) } else { // ex) trusted(prevSaved = 200), epochHeight = 400 must be finalized by min(410,latest) - checkpoint := trustedValidatorSet.Checkpoint(epochHeight) + checkpoint := trustedValidatorSet.Checkpoint(trustedTurnLength) + epochHeight limit := minUint64(checkpoint-1, latestHeight.GetRevisionHeight()) return queryVerifiableHeader(epochHeight, limit) } } -func setupNonNeighboringEpochHeader( - getHeader getHeaderFn, - queryVerifiableHeader queryVerifiableNonNeighboringEpochHeaderFn, - epochHeight uint64, - trustedEpochHeight uint64, - latestHeight exported.Height, -) (core.Header, error) { - currentValidatorSet, err := queryValidatorSet(getHeader, epochHeight) - if err != nil { - return nil, fmt.Errorf("setupNonNeighboringEpochHeader: failed to get curent validator set: trustedEpochHeight=%d : %+v", trustedEpochHeight, err) - } - trustedValidatorSet, err := queryValidatorSet(getHeader, trustedEpochHeight) - if err != nil { - return nil, fmt.Errorf("setupNonNeighboringEpochHeader: failed to get trusted validator set: trustedEpochHeight=%d : %+v", trustedEpochHeight, err) - } - if !trustedValidatorSet.Contains(currentValidatorSet) { - // It is recommended to recreate the Client. - return nil, fmt.Errorf("setupNonNeighboringEpochHeader: invalid untrusted validator set: epochHeight=%d, trustedEpochHeight=%d", epochHeight, trustedEpochHeight) - } - - // ex) trusted(prevSaved = 200), epochHeight = 600 must be finalized from 611 to min(810,latest) - nextCheckpoint := currentValidatorSet.Checkpoint(epochHeight + constant.BlocksPerEpoch) - limit := minUint64(nextCheckpoint-1, latestHeight.GetRevisionHeight()) - - // Headers after checkpoint are required to verify - previousValidatorSet, err := queryValidatorSet(getHeader, epochHeight-constant.BlocksPerEpoch) - if err != nil { - return nil, fmt.Errorf("setupNonNeighboringEpochHeader: failed to get previous validator set: epochHeight=%d : %+v", epochHeight-constant.BlocksPerEpoch, err) - } - checkpoint := previousValidatorSet.Checkpoint(epochHeight) - if checkpoint+2 > limit { - // Must wait more header - return nil, nil - } - h, err := queryVerifiableHeader(epochHeight, limit, checkpoint) - if h != nil { - // Override CurrentValidator to trusted validator set - // https://github.com/datachainlab/parlia-elc/blob/ce3611c3278508c97d41afed1be38b889602a1b1/light-client/src/header/mod.rs#L132 - h.(*Header).CurrentValidators = trustedValidatorSet - } - return h, err -} - func withTrustedHeight(targetHeaders []core.Header, clientStateLatestHeight exported.Height) []core.Header { logger := log.GetLogger() for i, h := range targetHeaders { diff --git a/module/setup_test.go b/module/setup_test.go index 21284c1..9e38d25 100644 --- a/module/setup_test.go +++ b/module/setup_test.go @@ -4,13 +4,11 @@ import ( "context" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" "github.com/datachainlab/ibc-parlia-relay/module/constant" - "github.com/ethereum/go-ethereum/common" types2 "github.com/ethereum/go-ethereum/core/types" "github.com/hyperledger-labs/yui-relayer/core" "github.com/hyperledger-labs/yui-relayer/log" "github.com/stretchr/testify/suite" "math/big" - "strings" "testing" ) @@ -48,17 +46,14 @@ func (ts *SetupTestSuite) TestSuccess_setupHeadersForUpdate_neighboringEpoch() { Headers: []*ETHHeader{h}, }, e } - nonNeighborFn := func(height uint64, _ uint64, _ uint64) (core.Header, error) { - return nil, nil - } headerFn := func(_ context.Context, height uint64) (*types2.Header, error) { return &types2.Header{ Number: big.NewInt(int64(height)), - Extra: common.Hex2Bytes("d88301020a846765746888676f312e32302e35856c696e7578000000b19df4a2150bac492386862ad3df4b666bc096b0505bb694dab0bec348681af766751cb839576e9c515a09c8bffa30a46296ccc56612490eb480d03bf948e10005bbcc0421f90b3d4e2465176c461afb316ebc773c61faee85a6515daa8a923564c6ffd37fb2fe9f118ef88092e8762c7addb526ab7eb1e772baef85181f892c731be0c1891a50e6b06262c816295e26495cef6f69dfa69911d9d8e4f3bbadb89b977cf58294f7239d515e15b24cfeb82494056cf691eaf729b165f32c9757c429dba5051155903067e56ebe3698678e9135ebb5849518aff370ca25e19e1072cc1a9fabcaa7f3e2c0b4b16ad183c473bafe30a36e39fa4a143657e229cd23c77f8fbc8e4e4e241695dd3d248d1e51521eee6619143f349bbafec1551819b8be1efea2fc46ca749aa184248a459464eec1a21e7fc7b71a053d9644e9bb8da4853b8f872cd7c1d6b324bf1922829830646ceadfb658d3de009a61dd481a114a2e761c554b641742c973867899d38a80967d39e406a0a9642d41e9007a27fc1150a267d143a9f786cd2b5eecbdcc4036273705225b956d5e2f8f5eb95d2569c77a677c40c7fbea129d4b171a39b7a8ddabfab2317f59d86abfaf690850223d90e9e7593d91a29331dfc2f84d5adecc75fc39ecab4632c1b4400a3dd1e1298835bcca70f657164e5b75689b64b7fd1fa275f334f28e1896a26afa1295da81418593bd12814463d9f6e45c36a0e47eb4cd3e5b6af29c41e2a3a5636430155a466e216585af3ba772b61c6014342d914470ec7ac2975be345796c2b81db0422a5fd08e40db1fc2368d2245e4b18b1d0b85c921aaaafd2e341760e29fc613edd39f71254614e2055c3287a517ae2f5b9e386cd1b50a4550696d957cb4900f03ab84f83ff2df44193496793b847f64e9d6db1b3953682bb95edd096eb1e69bbd357c200992ca78050d0cbe180cfaa018e8b6c8fd93d6f4cea42bbb345dbc6f0dfdb5bec73a8a257074e82b881cfa06ef3eb4efeca060c2531359abd0eab8af1e3edfa2025fca464ac9c3fd123f6c24a0d78869485a6f79b60359f141df90a0c745125b131caaffd12b772e180fbf38a051c97dabc8aaa0126a233a9e828cdafcc7422c4bb1f4030a56ba364c54103f26bad91508b5220b741b218c5d6af1f979ac42bc68d98a5a0d796c6ab01b659ad0fbd9f515893fdd740b29ba0772dbde9b4635921dd91bd2963a0fc855e31f6338f45b211c4e9dedb7f2eb09de7b4dd66d7c2c7e57f628210187192fb89d4b99dd4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000be807dddb074639cd9fa61b47676c064fc50d62cb1f2c71577def3144fabeb75a8a1c8cb5b51d1d1b4a05eec67988b8685008baa17459ec425dbaebc852f496dc92196cdcc8e6d00c17eb431350c6c50d8b8f05176b90b11b3a3d4feb825ae9702711566df5dbf38e82add4dd1b573b95d2466fa6501ccb81e9d26a352b96150ccbf7b697fd0a419d1d6bf74282782b0b3eb1413c901d6ecf02e8e28939e8fb41b682372335be8070199ad3e8621d1743bcac4cc9d8f0f6e10f41e56461385c8eb5daac804fe3f2bca6ce739d93dbfb27e027f5e9e6da52b9e1c413ce35adc11000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ea0a6e3c511bbd10f4519ece37dc24887e11b55db2d4c6283c44a1c7bd503aaba7666e9f0c830e0ff016c1c750a5e48757a713d0836b1cabfd5c281b1de3b77d1c192183ee226379db83cffc681495730c11fdde79ba4c0cae7bc6faa3f0cc3e6093b633fd7ee4f86970926958d0b7ec80437f936acf212b78f0cd095f4565fff144fd458d233a5bef0274e31810c9df02f98fafde0f841f4e66a1cd000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f8b5830aefffb86097bc63a64e8d730014c39dcaac8f3309e37a11c06f0f5c233b55ba19c1f6c34d2d08de4b030ce825bb21fd884bc0fcb811336857419f5ca42a92ac149a4661a248de10f4ca6496069fdfd10d43bc74ccb81806b6ecd384617d1006b16dead7e4f84c8401dd8eaea0e61c6075d2ab24fcdc423764c21771cac6b241cbff89718f9cc8fc6459b4e7578401dd8eafa010c8358490a494a40c5c92aff8628fa770860a9d34e7fb7df38dfb208b0ddfc380ff15abfc44495e4d4605458bb485f0cac5a152b380a8d0208b3f9ff6216230ec4dd67a73b72b1d17a888c68e111f806ef0b255d012b5185b7420b5fb529c9b9300"), + Extra: epochHeader().Extra, }, nil } - targets, err := setupHeadersForUpdate(neighborFn, nonNeighborFn, headerFn, clientStateLatestHeight, latestFinalizedHeader, clienttypes.NewHeight(0, 100000)) + targets, err := setupHeadersForUpdate(neighborFn, headerFn, clientStateLatestHeight, latestFinalizedHeader, clienttypes.NewHeight(0, 100000)) ts.Require().NoError(err) ts.Require().Len(targets, expected) for i, h := range targets { @@ -95,191 +90,6 @@ func (ts *SetupTestSuite) TestSuccess_setupHeadersForUpdate_neighboringEpoch() { } -func (ts *SetupTestSuite) TestSuccess_setupHeadersForUpdate_nonNeighboringEpoch() { - - verify := func(latestHeight, nextHeight uint64, expectedEpochs []int64, enableFast bool) { - clientStateLatestHeight := clienttypes.NewHeight(0, latestHeight) - target, err := newETHHeader(&types2.Header{ - Number: big.NewInt(int64(nextHeight)), - }) - ts.Require().NoError(err) - latestFinalizedHeader := &Header{ - Headers: []*ETHHeader{target}, - CurrentValidators: [][]byte{{1}}, - PreviousValidators: [][]byte{{1}}, - } - queryVerifyingNeighboringEpochHeader := func(_ uint64, _ uint64) (core.Header, error) { - return nil, nil - } - t := true - canVerify := &enableFast - queryVerifyingNonNeighboringEpochHeader := func(height, limit, checkpoint uint64) (core.Header, error) { - if !*canVerify { - canVerify = &t - return nil, nil - } - hs := make([]*ETHHeader, 0) - for i := height; i <= checkpoint+2; i++ { - if i > limit { - break - } - h, e := newETHHeader(&types2.Header{ - Number: big.NewInt(int64(i)), - }) - ts.Require().NoError(e) - hs = append(hs, h) - } - return &Header{ - Headers: hs, - }, nil - } - headerFn := func(_ context.Context, height uint64) (*types2.Header, error) { - return &types2.Header{ - Number: big.NewInt(int64(height)), - Extra: common.Hex2Bytes("d88301020a846765746888676f312e32302e35856c696e7578000000b19df4a2150bac492386862ad3df4b666bc096b0505bb694dab0bec348681af766751cb839576e9c515a09c8bffa30a46296ccc56612490eb480d03bf948e10005bbcc0421f90b3d4e2465176c461afb316ebc773c61faee85a6515daa8a923564c6ffd37fb2fe9f118ef88092e8762c7addb526ab7eb1e772baef85181f892c731be0c1891a50e6b06262c816295e26495cef6f69dfa69911d9d8e4f3bbadb89b977cf58294f7239d515e15b24cfeb82494056cf691eaf729b165f32c9757c429dba5051155903067e56ebe3698678e9135ebb5849518aff370ca25e19e1072cc1a9fabcaa7f3e2c0b4b16ad183c473bafe30a36e39fa4a143657e229cd23c77f8fbc8e4e4e241695dd3d248d1e51521eee6619143f349bbafec1551819b8be1efea2fc46ca749aa184248a459464eec1a21e7fc7b71a053d9644e9bb8da4853b8f872cd7c1d6b324bf1922829830646ceadfb658d3de009a61dd481a114a2e761c554b641742c973867899d38a80967d39e406a0a9642d41e9007a27fc1150a267d143a9f786cd2b5eecbdcc4036273705225b956d5e2f8f5eb95d2569c77a677c40c7fbea129d4b171a39b7a8ddabfab2317f59d86abfaf690850223d90e9e7593d91a29331dfc2f84d5adecc75fc39ecab4632c1b4400a3dd1e1298835bcca70f657164e5b75689b64b7fd1fa275f334f28e1896a26afa1295da81418593bd12814463d9f6e45c36a0e47eb4cd3e5b6af29c41e2a3a5636430155a466e216585af3ba772b61c6014342d914470ec7ac2975be345796c2b81db0422a5fd08e40db1fc2368d2245e4b18b1d0b85c921aaaafd2e341760e29fc613edd39f71254614e2055c3287a517ae2f5b9e386cd1b50a4550696d957cb4900f03ab84f83ff2df44193496793b847f64e9d6db1b3953682bb95edd096eb1e69bbd357c200992ca78050d0cbe180cfaa018e8b6c8fd93d6f4cea42bbb345dbc6f0dfdb5bec73a8a257074e82b881cfa06ef3eb4efeca060c2531359abd0eab8af1e3edfa2025fca464ac9c3fd123f6c24a0d78869485a6f79b60359f141df90a0c745125b131caaffd12b772e180fbf38a051c97dabc8aaa0126a233a9e828cdafcc7422c4bb1f4030a56ba364c54103f26bad91508b5220b741b218c5d6af1f979ac42bc68d98a5a0d796c6ab01b659ad0fbd9f515893fdd740b29ba0772dbde9b4635921dd91bd2963a0fc855e31f6338f45b211c4e9dedb7f2eb09de7b4dd66d7c2c7e57f628210187192fb89d4b99dd4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000be807dddb074639cd9fa61b47676c064fc50d62cb1f2c71577def3144fabeb75a8a1c8cb5b51d1d1b4a05eec67988b8685008baa17459ec425dbaebc852f496dc92196cdcc8e6d00c17eb431350c6c50d8b8f05176b90b11b3a3d4feb825ae9702711566df5dbf38e82add4dd1b573b95d2466fa6501ccb81e9d26a352b96150ccbf7b697fd0a419d1d6bf74282782b0b3eb1413c901d6ecf02e8e28939e8fb41b682372335be8070199ad3e8621d1743bcac4cc9d8f0f6e10f41e56461385c8eb5daac804fe3f2bca6ce739d93dbfb27e027f5e9e6da52b9e1c413ce35adc11000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ea0a6e3c511bbd10f4519ece37dc24887e11b55db2d4c6283c44a1c7bd503aaba7666e9f0c830e0ff016c1c750a5e48757a713d0836b1cabfd5c281b1de3b77d1c192183ee226379db83cffc681495730c11fdde79ba4c0cae7bc6faa3f0cc3e6093b633fd7ee4f86970926958d0b7ec80437f936acf212b78f0cd095f4565fff144fd458d233a5bef0274e31810c9df02f98fafde0f841f4e66a1cd000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f8b5830aefffb86097bc63a64e8d730014c39dcaac8f3309e37a11c06f0f5c233b55ba19c1f6c34d2d08de4b030ce825bb21fd884bc0fcb811336857419f5ca42a92ac149a4661a248de10f4ca6496069fdfd10d43bc74ccb81806b6ecd384617d1006b16dead7e4f84c8401dd8eaea0e61c6075d2ab24fcdc423764c21771cac6b241cbff89718f9cc8fc6459b4e7578401dd8eafa010c8358490a494a40c5c92aff8628fa770860a9d34e7fb7df38dfb208b0ddfc380ff15abfc44495e4d4605458bb485f0cac5a152b380a8d0208b3f9ff6216230ec4dd67a73b72b1d17a888c68e111f806ef0b255d012b5185b7420b5fb529c9b9300"), - }, nil - } - - targets, err := setupHeadersForUpdate(queryVerifyingNeighboringEpochHeader, queryVerifyingNonNeighboringEpochHeader, headerFn, clientStateLatestHeight, latestFinalizedHeader, clienttypes.NewHeight(0, 1000000)) - ts.Require().NoError(err) - ts.Require().Len(targets, len(expectedEpochs)) - for i, h := range targets { - targetHeader, _ := h.(*Header).Target() - ts.Require().Equal(targetHeader.Number.Int64(), expectedEpochs[i]) - - trusted := h.(*Header).TrustedHeight - if i == 0 { - ts.Require().Equal(trusted.RevisionHeight, latestHeight) - } else { - ts.Require().Equal(*trusted, targets[i-1].GetHeight()) - } - } - } - - verify(0, constant.BlocksPerEpoch-1, []int64{int64(constant.BlocksPerEpoch - 1)}, false) - verify(0, constant.BlocksPerEpoch-1, []int64{int64(constant.BlocksPerEpoch - 1)}, true) - verify(0, constant.BlocksPerEpoch, []int64{}, false) - verify(0, constant.BlocksPerEpoch, []int64{}, true) - verify(0, constant.BlocksPerEpoch+1, []int64{}, false) - verify(0, constant.BlocksPerEpoch+1, []int64{}, true) - verify(0, 10*constant.BlocksPerEpoch-1, []int64{400, 800, 1200, 1600}, false) - verify(0, 10*constant.BlocksPerEpoch-1, []int64{1800, 1999}, true) - verify(0, 10*constant.BlocksPerEpoch, []int64{400, 800, 1200, 1600, 2000}, false) - verify(0, 10*constant.BlocksPerEpoch, []int64{2000}, true) - verify(0, 10*constant.BlocksPerEpoch+1, []int64{400, 800, 1200, 1600, 2000, 2001}, false) - verify(0, 10*constant.BlocksPerEpoch+1, []int64{2000, 2001}, true) - verify(constant.BlocksPerEpoch-1, constant.BlocksPerEpoch-1, []int64{}, false) - verify(constant.BlocksPerEpoch-1, constant.BlocksPerEpoch-1, []int64{}, true) - verify(constant.BlocksPerEpoch-1, constant.BlocksPerEpoch, []int64{}, false) - verify(constant.BlocksPerEpoch-1, constant.BlocksPerEpoch, []int64{}, true) - verify(constant.BlocksPerEpoch-1, constant.BlocksPerEpoch+1, []int64{}, false) - verify(constant.BlocksPerEpoch-1, constant.BlocksPerEpoch+1, []int64{}, true) - verify(constant.BlocksPerEpoch-1, 10*constant.BlocksPerEpoch-1, []int64{400, 800, 1200, 1600}, false) - verify(constant.BlocksPerEpoch-1, 10*constant.BlocksPerEpoch-1, []int64{1800, 1999}, true) - verify(constant.BlocksPerEpoch-1, 10*constant.BlocksPerEpoch, []int64{400, 800, 1200, 1600, 2000}, false) - verify(constant.BlocksPerEpoch-1, 10*constant.BlocksPerEpoch, []int64{2000}, true) - verify(constant.BlocksPerEpoch-1, 10*constant.BlocksPerEpoch+1, []int64{400, 800, 1200, 1600, 2000, 2001}, false) - verify(constant.BlocksPerEpoch-1, 10*constant.BlocksPerEpoch+1, []int64{2000, 2001}, true) - verify(constant.BlocksPerEpoch, constant.BlocksPerEpoch, []int64{}, false) - verify(constant.BlocksPerEpoch, constant.BlocksPerEpoch, []int64{}, true) - verify(constant.BlocksPerEpoch, constant.BlocksPerEpoch+1, []int64{int64(constant.BlocksPerEpoch + 1)}, false) - verify(constant.BlocksPerEpoch, constant.BlocksPerEpoch+1, []int64{int64(constant.BlocksPerEpoch + 1)}, true) - verify(constant.BlocksPerEpoch, 10*constant.BlocksPerEpoch-1, []int64{600, 1000, 1400, 1800, 1999}, false) - verify(constant.BlocksPerEpoch, 10*constant.BlocksPerEpoch-1, []int64{1800, 1999}, true) - verify(constant.BlocksPerEpoch, 10*constant.BlocksPerEpoch, []int64{600, 1000, 1400, 1800}, false) - verify(constant.BlocksPerEpoch, 10*constant.BlocksPerEpoch, []int64{2000}, true) - verify(constant.BlocksPerEpoch, 10*constant.BlocksPerEpoch+1, []int64{600, 1000, 1400, 1800}, false) - verify(constant.BlocksPerEpoch, 10*constant.BlocksPerEpoch+1, []int64{2000, 2001}, true) - verify(constant.BlocksPerEpoch+1, constant.BlocksPerEpoch+1, []int64{}, false) - verify(constant.BlocksPerEpoch+1, constant.BlocksPerEpoch+1, []int64{}, true) - verify(constant.BlocksPerEpoch+1, 10*constant.BlocksPerEpoch-1, []int64{600, 1000, 1400, 1800, 1999}, false) - verify(constant.BlocksPerEpoch+1, 10*constant.BlocksPerEpoch-1, []int64{1800, 1999}, true) - verify(constant.BlocksPerEpoch+1, 10*constant.BlocksPerEpoch, []int64{600, 1000, 1400, 1800}, false) - verify(constant.BlocksPerEpoch+1, 10*constant.BlocksPerEpoch, []int64{2000}, true) - verify(constant.BlocksPerEpoch+1, 10*constant.BlocksPerEpoch+1, []int64{600, 1000, 1400, 1800}, false) - verify(constant.BlocksPerEpoch+1, 10*constant.BlocksPerEpoch+1, []int64{2000, 2001}, true) - -} - -func (ts *SetupTestSuite) TestSuccess_setupHeadersForUpdate_nonNeighboringEpoch_checkpointOverLimit() { - - verify := func(latestHeight, nextHeight uint64, expectedEpochs []int64) { - clientStateLatestHeight := clienttypes.NewHeight(0, latestHeight) - target, err := newETHHeader(&types2.Header{ - Number: big.NewInt(int64(nextHeight)), - }) - ts.Require().NoError(err) - latestFinalizedHeader := &Header{ - Headers: []*ETHHeader{target}, - CurrentValidators: [][]byte{{1}}, - PreviousValidators: [][]byte{{1}}, - } - queryVerifyingNeighboringEpochHeader := func(_ uint64, _ uint64) (core.Header, error) { - return nil, nil - } - queryVerifyingNonNeighboringEpochHeader := func(height, limit, checkpoint uint64) (core.Header, error) { - hs := make([]*ETHHeader, 0) - for i := height; i <= checkpoint+2; i++ { - if i > limit { - break - } - h, e := newETHHeader(&types2.Header{ - Number: big.NewInt(int64(i)), - }) - ts.Require().NoError(e) - hs = append(hs, h) - } - return &Header{ - Headers: hs, - }, nil - } - headerFn := func(_ context.Context, height uint64) (*types2.Header, error) { - return &types2.Header{ - Number: big.NewInt(int64(height)), - Extra: common.Hex2Bytes("d88301020a846765746888676f312e32302e35856c696e7578000000b19df4a2150bac492386862ad3df4b666bc096b0505bb694dab0bec348681af766751cb839576e9c515a09c8bffa30a46296ccc56612490eb480d03bf948e10005bbcc0421f90b3d4e2465176c461afb316ebc773c61faee85a6515daa8a923564c6ffd37fb2fe9f118ef88092e8762c7addb526ab7eb1e772baef85181f892c731be0c1891a50e6b06262c816295e26495cef6f69dfa69911d9d8e4f3bbadb89b977cf58294f7239d515e15b24cfeb82494056cf691eaf729b165f32c9757c429dba5051155903067e56ebe3698678e9135ebb5849518aff370ca25e19e1072cc1a9fabcaa7f3e2c0b4b16ad183c473bafe30a36e39fa4a143657e229cd23c77f8fbc8e4e4e241695dd3d248d1e51521eee6619143f349bbafec1551819b8be1efea2fc46ca749aa184248a459464eec1a21e7fc7b71a053d9644e9bb8da4853b8f872cd7c1d6b324bf1922829830646ceadfb658d3de009a61dd481a114a2e761c554b641742c973867899d38a80967d39e406a0a9642d41e9007a27fc1150a267d143a9f786cd2b5eecbdcc4036273705225b956d5e2f8f5eb95d2569c77a677c40c7fbea129d4b171a39b7a8ddabfab2317f59d86abfaf690850223d90e9e7593d91a29331dfc2f84d5adecc75fc39ecab4632c1b4400a3dd1e1298835bcca70f657164e5b75689b64b7fd1fa275f334f28e1896a26afa1295da81418593bd12814463d9f6e45c36a0e47eb4cd3e5b6af29c41e2a3a5636430155a466e216585af3ba772b61c6014342d914470ec7ac2975be345796c2b81db0422a5fd08e40db1fc2368d2245e4b18b1d0b85c921aaaafd2e341760e29fc613edd39f71254614e2055c3287a517ae2f5b9e386cd1b50a4550696d957cb4900f03ab84f83ff2df44193496793b847f64e9d6db1b3953682bb95edd096eb1e69bbd357c200992ca78050d0cbe180cfaa018e8b6c8fd93d6f4cea42bbb345dbc6f0dfdb5bec73a8a257074e82b881cfa06ef3eb4efeca060c2531359abd0eab8af1e3edfa2025fca464ac9c3fd123f6c24a0d78869485a6f79b60359f141df90a0c745125b131caaffd12b772e180fbf38a051c97dabc8aaa0126a233a9e828cdafcc7422c4bb1f4030a56ba364c54103f26bad91508b5220b741b218c5d6af1f979ac42bc68d98a5a0d796c6ab01b659ad0fbd9f515893fdd740b29ba0772dbde9b4635921dd91bd2963a0fc855e31f6338f45b211c4e9dedb7f2eb09de7b4dd66d7c2c7e57f628210187192fb89d4b99dd4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000be807dddb074639cd9fa61b47676c064fc50d62cb1f2c71577def3144fabeb75a8a1c8cb5b51d1d1b4a05eec67988b8685008baa17459ec425dbaebc852f496dc92196cdcc8e6d00c17eb431350c6c50d8b8f05176b90b11b3a3d4feb825ae9702711566df5dbf38e82add4dd1b573b95d2466fa6501ccb81e9d26a352b96150ccbf7b697fd0a419d1d6bf74282782b0b3eb1413c901d6ecf02e8e28939e8fb41b682372335be8070199ad3e8621d1743bcac4cc9d8f0f6e10f41e56461385c8eb5daac804fe3f2bca6ce739d93dbfb27e027f5e9e6da52b9e1c413ce35adc11000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ea0a6e3c511bbd10f4519ece37dc24887e11b55db2d4c6283c44a1c7bd503aaba7666e9f0c830e0ff016c1c750a5e48757a713d0836b1cabfd5c281b1de3b77d1c192183ee226379db83cffc681495730c11fdde79ba4c0cae7bc6faa3f0cc3e6093b633fd7ee4f86970926958d0b7ec80437f936acf212b78f0cd095f4565fff144fd458d233a5bef0274e31810c9df02f98fafde0f841f4e66a1cd000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f8b5830aefffb86097bc63a64e8d730014c39dcaac8f3309e37a11c06f0f5c233b55ba19c1f6c34d2d08de4b030ce825bb21fd884bc0fcb811336857419f5ca42a92ac149a4661a248de10f4ca6496069fdfd10d43bc74ccb81806b6ecd384617d1006b16dead7e4f84c8401dd8eaea0e61c6075d2ab24fcdc423764c21771cac6b241cbff89718f9cc8fc6459b4e7578401dd8eafa010c8358490a494a40c5c92aff8628fa770860a9d34e7fb7df38dfb208b0ddfc380ff15abfc44495e4d4605458bb485f0cac5a152b380a8d0208b3f9ff6216230ec4dd67a73b72b1d17a888c68e111f806ef0b255d012b5185b7420b5fb529c9b9300"), - }, nil - } - - targets, err := setupHeadersForUpdate(queryVerifyingNeighboringEpochHeader, queryVerifyingNonNeighboringEpochHeader, headerFn, clientStateLatestHeight, latestFinalizedHeader, clienttypes.NewHeight(0, 1)) - ts.Require().NoError(err) - ts.Require().Len(targets, len(expectedEpochs)) - for i, h := range targets { - targetHeader, _ := h.(*Header).Target() - ts.Require().Equal(targetHeader.Number.Int64(), expectedEpochs[i]) - - trusted := h.(*Header).TrustedHeight - if i == 0 { - ts.Require().Equal(trusted.RevisionHeight, latestHeight) - } else { - ts.Require().Equal(*trusted, targets[i-1].GetHeight()) - } - } - } - - verify(0, constant.BlocksPerEpoch-1, []int64{int64(constant.BlocksPerEpoch - 1)}) - verify(0, constant.BlocksPerEpoch, []int64{}) - verify(0, constant.BlocksPerEpoch+1, []int64{}) - verify(0, 10*constant.BlocksPerEpoch-1, []int64{}) - verify(0, 10*constant.BlocksPerEpoch, []int64{}) - verify(0, 10*constant.BlocksPerEpoch+1, []int64{}) - verify(constant.BlocksPerEpoch-1, constant.BlocksPerEpoch-1, []int64{}) - verify(constant.BlocksPerEpoch-1, constant.BlocksPerEpoch, []int64{}) - verify(constant.BlocksPerEpoch-1, constant.BlocksPerEpoch+1, []int64{}) - verify(constant.BlocksPerEpoch-1, 10*constant.BlocksPerEpoch-1, []int64{}) - verify(constant.BlocksPerEpoch-1, 10*constant.BlocksPerEpoch, []int64{}) - verify(constant.BlocksPerEpoch-1, 10*constant.BlocksPerEpoch+1, []int64{}) - verify(constant.BlocksPerEpoch, constant.BlocksPerEpoch, []int64{}) - verify(constant.BlocksPerEpoch, constant.BlocksPerEpoch+1, []int64{int64(constant.BlocksPerEpoch + 1)}) - verify(constant.BlocksPerEpoch, 10*constant.BlocksPerEpoch-1, []int64{}) - verify(constant.BlocksPerEpoch, 10*constant.BlocksPerEpoch, []int64{}) - verify(constant.BlocksPerEpoch, 10*constant.BlocksPerEpoch+1, []int64{}) - verify(constant.BlocksPerEpoch+1, constant.BlocksPerEpoch+1, []int64{}) - verify(constant.BlocksPerEpoch+1, 10*constant.BlocksPerEpoch-1, []int64{}) - verify(constant.BlocksPerEpoch+1, 10*constant.BlocksPerEpoch, []int64{}) - verify(constant.BlocksPerEpoch+1, 10*constant.BlocksPerEpoch+1, []int64{}) - -} - func (ts *SetupTestSuite) TestSuccess_setupHeadersForUpdate_allEmpty() { verify := func(latestHeight, nextHeight uint64, expected int) { @@ -291,44 +101,42 @@ func (ts *SetupTestSuite) TestSuccess_setupHeadersForUpdate_allEmpty() { latestFinalizedHeader := &Header{ Headers: []*ETHHeader{target}, } - neighboringEpochFn := func(_ uint64, _ uint64) (core.Header, error) { - return nil, nil - } - nonNeighboringEpochFn := func(_ uint64, _, _ uint64) (core.Header, error) { + neighboringEpochFn := func(height uint64, _ uint64) (core.Header, error) { + // insufficient vote attestation return nil, nil } headerFn := func(_ context.Context, height uint64) (*types2.Header, error) { return &types2.Header{ Number: big.NewInt(int64(height)), - Extra: common.Hex2Bytes("d88301020a846765746888676f312e32302e35856c696e7578000000b19df4a2150bac492386862ad3df4b666bc096b0505bb694dab0bec348681af766751cb839576e9c515a09c8bffa30a46296ccc56612490eb480d03bf948e10005bbcc0421f90b3d4e2465176c461afb316ebc773c61faee85a6515daa8a923564c6ffd37fb2fe9f118ef88092e8762c7addb526ab7eb1e772baef85181f892c731be0c1891a50e6b06262c816295e26495cef6f69dfa69911d9d8e4f3bbadb89b977cf58294f7239d515e15b24cfeb82494056cf691eaf729b165f32c9757c429dba5051155903067e56ebe3698678e9135ebb5849518aff370ca25e19e1072cc1a9fabcaa7f3e2c0b4b16ad183c473bafe30a36e39fa4a143657e229cd23c77f8fbc8e4e4e241695dd3d248d1e51521eee6619143f349bbafec1551819b8be1efea2fc46ca749aa184248a459464eec1a21e7fc7b71a053d9644e9bb8da4853b8f872cd7c1d6b324bf1922829830646ceadfb658d3de009a61dd481a114a2e761c554b641742c973867899d38a80967d39e406a0a9642d41e9007a27fc1150a267d143a9f786cd2b5eecbdcc4036273705225b956d5e2f8f5eb95d2569c77a677c40c7fbea129d4b171a39b7a8ddabfab2317f59d86abfaf690850223d90e9e7593d91a29331dfc2f84d5adecc75fc39ecab4632c1b4400a3dd1e1298835bcca70f657164e5b75689b64b7fd1fa275f334f28e1896a26afa1295da81418593bd12814463d9f6e45c36a0e47eb4cd3e5b6af29c41e2a3a5636430155a466e216585af3ba772b61c6014342d914470ec7ac2975be345796c2b81db0422a5fd08e40db1fc2368d2245e4b18b1d0b85c921aaaafd2e341760e29fc613edd39f71254614e2055c3287a517ae2f5b9e386cd1b50a4550696d957cb4900f03ab84f83ff2df44193496793b847f64e9d6db1b3953682bb95edd096eb1e69bbd357c200992ca78050d0cbe180cfaa018e8b6c8fd93d6f4cea42bbb345dbc6f0dfdb5bec73a8a257074e82b881cfa06ef3eb4efeca060c2531359abd0eab8af1e3edfa2025fca464ac9c3fd123f6c24a0d78869485a6f79b60359f141df90a0c745125b131caaffd12b772e180fbf38a051c97dabc8aaa0126a233a9e828cdafcc7422c4bb1f4030a56ba364c54103f26bad91508b5220b741b218c5d6af1f979ac42bc68d98a5a0d796c6ab01b659ad0fbd9f515893fdd740b29ba0772dbde9b4635921dd91bd2963a0fc855e31f6338f45b211c4e9dedb7f2eb09de7b4dd66d7c2c7e57f628210187192fb89d4b99dd4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000be807dddb074639cd9fa61b47676c064fc50d62cb1f2c71577def3144fabeb75a8a1c8cb5b51d1d1b4a05eec67988b8685008baa17459ec425dbaebc852f496dc92196cdcc8e6d00c17eb431350c6c50d8b8f05176b90b11b3a3d4feb825ae9702711566df5dbf38e82add4dd1b573b95d2466fa6501ccb81e9d26a352b96150ccbf7b697fd0a419d1d6bf74282782b0b3eb1413c901d6ecf02e8e28939e8fb41b682372335be8070199ad3e8621d1743bcac4cc9d8f0f6e10f41e56461385c8eb5daac804fe3f2bca6ce739d93dbfb27e027f5e9e6da52b9e1c413ce35adc11000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ea0a6e3c511bbd10f4519ece37dc24887e11b55db2d4c6283c44a1c7bd503aaba7666e9f0c830e0ff016c1c750a5e48757a713d0836b1cabfd5c281b1de3b77d1c192183ee226379db83cffc681495730c11fdde79ba4c0cae7bc6faa3f0cc3e6093b633fd7ee4f86970926958d0b7ec80437f936acf212b78f0cd095f4565fff144fd458d233a5bef0274e31810c9df02f98fafde0f841f4e66a1cd000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f8b5830aefffb86097bc63a64e8d730014c39dcaac8f3309e37a11c06f0f5c233b55ba19c1f6c34d2d08de4b030ce825bb21fd884bc0fcb811336857419f5ca42a92ac149a4661a248de10f4ca6496069fdfd10d43bc74ccb81806b6ecd384617d1006b16dead7e4f84c8401dd8eaea0e61c6075d2ab24fcdc423764c21771cac6b241cbff89718f9cc8fc6459b4e7578401dd8eafa010c8358490a494a40c5c92aff8628fa770860a9d34e7fb7df38dfb208b0ddfc380ff15abfc44495e4d4605458bb485f0cac5a152b380a8d0208b3f9ff6216230ec4dd67a73b72b1d17a888c68e111f806ef0b255d012b5185b7420b5fb529c9b9300"), + Extra: epochHeader().Extra, }, nil } - targets, err := setupHeadersForUpdate(neighboringEpochFn, nonNeighboringEpochFn, headerFn, clientStateLatestHeight, latestFinalizedHeader, clienttypes.NewHeight(0, 1000000)) + targets, err := setupHeadersForUpdate(neighboringEpochFn, headerFn, clientStateLatestHeight, latestFinalizedHeader, clienttypes.NewHeight(0, 1000000)) ts.Require().NoError(err) ts.Require().Len(targets, expected) } - verify(0, constant.BlocksPerEpoch-1, 1) // latest non epoch finalized header exists - verify(0, constant.BlocksPerEpoch, 0) - verify(0, constant.BlocksPerEpoch+1, 0) + verify(0, constant.BlocksPerEpoch-1, 1) + verify(0, constant.BlocksPerEpoch, 1) + verify(0, constant.BlocksPerEpoch+1, 0) // non neighboring verify(0, 10*constant.BlocksPerEpoch-1, 0) - verify(0, 10*constant.BlocksPerEpoch, 0) - verify(0, 10*constant.BlocksPerEpoch+1, 0) - verify(constant.BlocksPerEpoch-1, constant.BlocksPerEpoch-1, 0) - verify(constant.BlocksPerEpoch-1, constant.BlocksPerEpoch, 0) - verify(constant.BlocksPerEpoch-1, constant.BlocksPerEpoch+1, 0) + verify(0, 10*constant.BlocksPerEpoch, 0) // non neighboring + verify(0, 10*constant.BlocksPerEpoch+1, 0) // non neighboring + verify(constant.BlocksPerEpoch-1, constant.BlocksPerEpoch-1, 0) // same + verify(constant.BlocksPerEpoch-1, constant.BlocksPerEpoch, 1) + verify(constant.BlocksPerEpoch-1, constant.BlocksPerEpoch+1, 0) // non neighboring verify(constant.BlocksPerEpoch-1, 10*constant.BlocksPerEpoch-1, 0) - verify(constant.BlocksPerEpoch-1, 10*constant.BlocksPerEpoch, 0) - verify(constant.BlocksPerEpoch-1, 10*constant.BlocksPerEpoch+1, 0) - verify(constant.BlocksPerEpoch, constant.BlocksPerEpoch, 0) - verify(constant.BlocksPerEpoch, constant.BlocksPerEpoch+1, 1) // latest non epoch finalized header exists - verify(constant.BlocksPerEpoch, 10*constant.BlocksPerEpoch-1, 0) - verify(constant.BlocksPerEpoch, 10*constant.BlocksPerEpoch, 0) - verify(constant.BlocksPerEpoch, 10*constant.BlocksPerEpoch+1, 0) - verify(constant.BlocksPerEpoch+1, constant.BlocksPerEpoch+1, 0) - verify(constant.BlocksPerEpoch+1, 10*constant.BlocksPerEpoch-1, 0) - verify(constant.BlocksPerEpoch+1, 10*constant.BlocksPerEpoch, 0) - verify(constant.BlocksPerEpoch+1, 10*constant.BlocksPerEpoch+1, 0) + verify(constant.BlocksPerEpoch-1, 10*constant.BlocksPerEpoch, 0) // non neighboring + verify(constant.BlocksPerEpoch-1, 10*constant.BlocksPerEpoch+1, 0) // non neighboring + verify(constant.BlocksPerEpoch, constant.BlocksPerEpoch, 0) // same + verify(constant.BlocksPerEpoch, constant.BlocksPerEpoch+1, 1) + verify(constant.BlocksPerEpoch, 10*constant.BlocksPerEpoch-1, 0) // non neighboring + verify(constant.BlocksPerEpoch, 10*constant.BlocksPerEpoch, 0) // non neighboring + verify(constant.BlocksPerEpoch, 10*constant.BlocksPerEpoch+1, 0) // non neighboring + verify(constant.BlocksPerEpoch+1, constant.BlocksPerEpoch+1, 0) // same + verify(constant.BlocksPerEpoch+1, 10*constant.BlocksPerEpoch-1, 0) // non neighboring + verify(constant.BlocksPerEpoch+1, 10*constant.BlocksPerEpoch, 0) // non neighboring + verify(constant.BlocksPerEpoch+1, 10*constant.BlocksPerEpoch+1, 0) // non neighboring } func (ts *SetupTestSuite) TestSuccess_setupNeighboringEpochHeader_notContainTrusted() { @@ -346,23 +154,27 @@ func (ts *SetupTestSuite) TestSuccess_setupNeighboringEpochHeader_notContainTrus }, nil } headerFn := func(_ context.Context, height uint64) (*types2.Header, error) { - extra := common.Hex2Bytes("d88301020a846765746888676f312e32302e35856c696e7578000000b19df4a2150bac492386862ad3df4b666bc096b0505bb694dab0bec348681af766751cb839576e9c515a09c8bffa30a46296ccc56612490eb480d03bf948e10005bbcc0421f90b3d4e2465176c461afb316ebc773c61faee85a6515daa8a923564c6ffd37fb2fe9f118ef88092e8762c7addb526ab7eb1e772baef85181f892c731be0c1891a50e6b06262c816295e26495cef6f69dfa69911d9d8e4f3bbadb89b977cf58294f7239d515e15b24cfeb82494056cf691eaf729b165f32c9757c429dba5051155903067e56ebe3698678e9135ebb5849518aff370ca25e19e1072cc1a9fabcaa7f3e2c0b4b16ad183c473bafe30a36e39fa4a143657e229cd23c77f8fbc8e4e4e241695dd3d248d1e51521eee6619143f349bbafec1551819b8be1efea2fc46ca749aa184248a459464eec1a21e7fc7b71a053d9644e9bb8da4853b8f872cd7c1d6b324bf1922829830646ceadfb658d3de009a61dd481a114a2e761c554b641742c973867899d38a80967d39e406a0a9642d41e9007a27fc1150a267d143a9f786cd2b5eecbdcc4036273705225b956d5e2f8f5eb95d2569c77a677c40c7fbea129d4b171a39b7a8ddabfab2317f59d86abfaf690850223d90e9e7593d91a29331dfc2f84d5adecc75fc39ecab4632c1b4400a3dd1e1298835bcca70f657164e5b75689b64b7fd1fa275f334f28e1896a26afa1295da81418593bd12814463d9f6e45c36a0e47eb4cd3e5b6af29c41e2a3a5636430155a466e216585af3ba772b61c6014342d914470ec7ac2975be345796c2b81db0422a5fd08e40db1fc2368d2245e4b18b1d0b85c921aaaafd2e341760e29fc613edd39f71254614e2055c3287a517ae2f5b9e386cd1b50a4550696d957cb4900f03ab84f83ff2df44193496793b847f64e9d6db1b3953682bb95edd096eb1e69bbd357c200992ca78050d0cbe180cfaa018e8b6c8fd93d6f4cea42bbb345dbc6f0dfdb5bec73a8a257074e82b881cfa06ef3eb4efeca060c2531359abd0eab8af1e3edfa2025fca464ac9c3fd123f6c24a0d78869485a6f79b60359f141df90a0c745125b131caaffd12b772e180fbf38a051c97dabc8aaa0126a233a9e828cdafcc7422c4bb1f4030a56ba364c54103f26bad91508b5220b741b218c5d6af1f979ac42bc68d98a5a0d796c6ab01b659ad0fbd9f515893fdd740b29ba0772dbde9b4635921dd91bd2963a0fc855e31f6338f45b211c4e9dedb7f2eb09de7b4dd66d7c2c7e57f628210187192fb89d4b99dd4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000be807dddb074639cd9fa61b47676c064fc50d62cb1f2c71577def3144fabeb75a8a1c8cb5b51d1d1b4a05eec67988b8685008baa17459ec425dbaebc852f496dc92196cdcc8e6d00c17eb431350c6c50d8b8f05176b90b11b3a3d4feb825ae9702711566df5dbf38e82add4dd1b573b95d2466fa6501ccb81e9d26a352b96150ccbf7b697fd0a419d1d6bf74282782b0b3eb1413c901d6ecf02e8e28939e8fb41b682372335be8070199ad3e8621d1743bcac4cc9d8f0f6e10f41e56461385c8eb5daac804fe3f2bca6ce739d93dbfb27e027f5e9e6da52b9e1c413ce35adc11000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ea0a6e3c511bbd10f4519ece37dc24887e11b55db2d4c6283c44a1c7bd503aaba7666e9f0c830e0ff016c1c750a5e48757a713d0836b1cabfd5c281b1de3b77d1c192183ee226379db83cffc681495730c11fdde79ba4c0cae7bc6faa3f0cc3e6093b633fd7ee4f86970926958d0b7ec80437f936acf212b78f0cd095f4565fff144fd458d233a5bef0274e31810c9df02f98fafde0f841f4e66a1cd000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f8b5830aefffb86097bc63a64e8d730014c39dcaac8f3309e37a11c06f0f5c233b55ba19c1f6c34d2d08de4b030ce825bb21fd884bc0fcb811336857419f5ca42a92ac149a4661a248de10f4ca6496069fdfd10d43bc74ccb81806b6ecd384617d1006b16dead7e4f84c8401dd8eaea0e61c6075d2ab24fcdc423764c21771cac6b241cbff89718f9cc8fc6459b4e7578401dd8eafa010c8358490a494a40c5c92aff8628fa770860a9d34e7fb7df38dfb208b0ddfc380ff15abfc44495e4d4605458bb485f0cac5a152b380a8d0208b3f9ff6216230ec4dd67a73b72b1d17a888c68e111f806ef0b255d012b5185b7420b5fb529c9b9300") - if height == trustedEpochHeight { - // testnet validator (size = 6) - extra = common.Hex2Bytes("d983010306846765746889676f312e32302e3131856c696e7578000053474aa9061284214b9b9c85549ab3d2b972df0deef66ac2c98e82934ca974fdcd97f3309de967d3c9c43fa711a8d673af5d75465844bf8969c8d1948d903748ac7b8b1720fa64e50c35552c16704d214347f29fa77f77da6d75d7c752b742ad4855bae330426b823e742da31f816cc83bc16d69a9134be0cfb4a1d17ec34f1b5b32d5c20440b8536b1e88f0f2980a75ecd1309ea12fa2ed87a8744fbfc9b863d589037a9ace3b590165ea1c0c5ac72bf600b7c88c1e435f41932c1132aae1bfa0bb68e46b96ccb12c3415e4d82af717d8a2959d3f95eae5dc7d70144ce1b73b403b7eb6e0b973c2d38487e58fd6e145491b110080fb14ac915a0411fc78f19e09a399ddee0d20c63a75d8f930f1694544ad2dc01bb71b214cb885500844365e95cd9942c7276e7fd8a2750ec6dded3dcdc2f351782310b0eadc077db59abca0f0cd26776e2e7acb9f3bce40b1fa5221fd1561226c6263cc5ff474cf03cceff28abc65c9cbae594f725c80e12d96c9b86c3400e529bfe184056e257c07940bb664636f689e8d2027c834681f8f878b73445261034e946bb2d901b4b878f8b23fb860a2e980e217c681cb143f623fd5f9f621f6ff6744aef8e8eac63c68750700d0fc90e764516a9eaf069dae86e8f9db5c32037e33b610b88e180abe6c7cb44fe7291bbbf502d4a93b45b19214a6135d5b043c74d9b040969eb8a0ed038f3283173ff84c840231b4dea02c4e09f3cb878f41d53efbb15dcf08cab13455b16b9bbcfc7bd4e35de0a63e17840231b4dfa0c0931c8edab5ab5979a0762d3516367c2f44cecb5070db0ff7a4af46fc5073ee80672779b27abd01b3cff88b18684bbdc4a42009d1c8335e309dde3049c1ab0b0f457f75667781c9380994a6a92bb47c216f986252b2a8e82874307243c15e7f1b01") + h := headerByHeight(int64(height)) + const validatorCount = 4 + const indexOfValidatorCount = extraVanity + const indexOfTurnLength = extraVanity + validatorNumberSize + validatorCount*validatorBytesLength + if h.Number.Uint64() == trustedEpochHeight { + // set invalid validator + for i := range h.Extra { + if i != indexOfValidatorCount && i != indexOfTurnLength { + h.Extra[i] = 0 + } + } } - return &types2.Header{ - Number: big.NewInt(int64(height)), - Extra: extra, - }, nil + return h, nil } - hs, err := setupNeighboringEpochHeader(headerFn, neighboringEpochFn, epochHeight, trustedEpochHeight, clienttypes.NewHeight(0, 1000000)) + hs, err := setupNeighboringEpochHeader(headerFn, neighboringEpochFn, epochHeight, trustedEpochHeight, clienttypes.NewHeight(0, 10000)) ts.Require().NoError(err) target, err := hs.(*Header).Target() ts.Require().NoError(err) // checkpoint - 1 - ts.Require().Equal(int64(403), target.Number.Int64()) + ts.Require().Equal(int64(402), target.Number.Int64()) } func (ts *SetupTestSuite) TestSuccess_setupNeighboringEpochHeader_containTrusted() { @@ -380,99 +192,13 @@ func (ts *SetupTestSuite) TestSuccess_setupNeighboringEpochHeader_containTrusted }, nil } headerFn := func(_ context.Context, height uint64) (*types2.Header, error) { - extra := common.Hex2Bytes("d88301020a846765746888676f312e32302e35856c696e7578000000b19df4a2150bac492386862ad3df4b666bc096b0505bb694dab0bec348681af766751cb839576e9c515a09c8bffa30a46296ccc56612490eb480d03bf948e10005bbcc0421f90b3d4e2465176c461afb316ebc773c61faee85a6515daa8a923564c6ffd37fb2fe9f118ef88092e8762c7addb526ab7eb1e772baef85181f892c731be0c1891a50e6b06262c816295e26495cef6f69dfa69911d9d8e4f3bbadb89b977cf58294f7239d515e15b24cfeb82494056cf691eaf729b165f32c9757c429dba5051155903067e56ebe3698678e9135ebb5849518aff370ca25e19e1072cc1a9fabcaa7f3e2c0b4b16ad183c473bafe30a36e39fa4a143657e229cd23c77f8fbc8e4e4e241695dd3d248d1e51521eee6619143f349bbafec1551819b8be1efea2fc46ca749aa184248a459464eec1a21e7fc7b71a053d9644e9bb8da4853b8f872cd7c1d6b324bf1922829830646ceadfb658d3de009a61dd481a114a2e761c554b641742c973867899d38a80967d39e406a0a9642d41e9007a27fc1150a267d143a9f786cd2b5eecbdcc4036273705225b956d5e2f8f5eb95d2569c77a677c40c7fbea129d4b171a39b7a8ddabfab2317f59d86abfaf690850223d90e9e7593d91a29331dfc2f84d5adecc75fc39ecab4632c1b4400a3dd1e1298835bcca70f657164e5b75689b64b7fd1fa275f334f28e1896a26afa1295da81418593bd12814463d9f6e45c36a0e47eb4cd3e5b6af29c41e2a3a5636430155a466e216585af3ba772b61c6014342d914470ec7ac2975be345796c2b81db0422a5fd08e40db1fc2368d2245e4b18b1d0b85c921aaaafd2e341760e29fc613edd39f71254614e2055c3287a517ae2f5b9e386cd1b50a4550696d957cb4900f03ab84f83ff2df44193496793b847f64e9d6db1b3953682bb95edd096eb1e69bbd357c200992ca78050d0cbe180cfaa018e8b6c8fd93d6f4cea42bbb345dbc6f0dfdb5bec73a8a257074e82b881cfa06ef3eb4efeca060c2531359abd0eab8af1e3edfa2025fca464ac9c3fd123f6c24a0d78869485a6f79b60359f141df90a0c745125b131caaffd12b772e180fbf38a051c97dabc8aaa0126a233a9e828cdafcc7422c4bb1f4030a56ba364c54103f26bad91508b5220b741b218c5d6af1f979ac42bc68d98a5a0d796c6ab01b659ad0fbd9f515893fdd740b29ba0772dbde9b4635921dd91bd2963a0fc855e31f6338f45b211c4e9dedb7f2eb09de7b4dd66d7c2c7e57f628210187192fb89d4b99dd4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000be807dddb074639cd9fa61b47676c064fc50d62cb1f2c71577def3144fabeb75a8a1c8cb5b51d1d1b4a05eec67988b8685008baa17459ec425dbaebc852f496dc92196cdcc8e6d00c17eb431350c6c50d8b8f05176b90b11b3a3d4feb825ae9702711566df5dbf38e82add4dd1b573b95d2466fa6501ccb81e9d26a352b96150ccbf7b697fd0a419d1d6bf74282782b0b3eb1413c901d6ecf02e8e28939e8fb41b682372335be8070199ad3e8621d1743bcac4cc9d8f0f6e10f41e56461385c8eb5daac804fe3f2bca6ce739d93dbfb27e027f5e9e6da52b9e1c413ce35adc11000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ea0a6e3c511bbd10f4519ece37dc24887e11b55db2d4c6283c44a1c7bd503aaba7666e9f0c830e0ff016c1c750a5e48757a713d0836b1cabfd5c281b1de3b77d1c192183ee226379db83cffc681495730c11fdde79ba4c0cae7bc6faa3f0cc3e6093b633fd7ee4f86970926958d0b7ec80437f936acf212b78f0cd095f4565fff144fd458d233a5bef0274e31810c9df02f98fafde0f841f4e66a1cd000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f8b5830aefffb86097bc63a64e8d730014c39dcaac8f3309e37a11c06f0f5c233b55ba19c1f6c34d2d08de4b030ce825bb21fd884bc0fcb811336857419f5ca42a92ac149a4661a248de10f4ca6496069fdfd10d43bc74ccb81806b6ecd384617d1006b16dead7e4f84c8401dd8eaea0e61c6075d2ab24fcdc423764c21771cac6b241cbff89718f9cc8fc6459b4e7578401dd8eafa010c8358490a494a40c5c92aff8628fa770860a9d34e7fb7df38dfb208b0ddfc380ff15abfc44495e4d4605458bb485f0cac5a152b380a8d0208b3f9ff6216230ec4dd67a73b72b1d17a888c68e111f806ef0b255d012b5185b7420b5fb529c9b9300") - return &types2.Header{ - Number: big.NewInt(int64(height)), - Extra: extra, - }, nil + return headerByHeight(int64(height)), nil } - hs, err := setupNeighboringEpochHeader(headerFn, neighboringEpochFn, epochHeight, trustedEpochHeight, clienttypes.NewHeight(0, 1000000)) + hs, err := setupNeighboringEpochHeader(headerFn, neighboringEpochFn, epochHeight, trustedEpochHeight, clienttypes.NewHeight(0, 10000)) ts.Require().NoError(err) target, err := hs.(*Header).Target() ts.Require().NoError(err) // next checkpoint - 1 - ts.Require().Equal(int64(610), target.Number.Int64()) -} - -func (ts *SetupTestSuite) TestSuccess_setupNonNeighboringEpochHeader_containTrusted() { - - epochHeight := uint64(600) - trustedEpochHeight := uint64(200) - - nonNeighboringEpochFn := func(height uint64, limit uint64, checkpoint uint64) (core.Header, error) { - h1, e := newETHHeader(&types2.Header{ - Number: big.NewInt(int64(checkpoint)), - }) - ts.Require().NoError(e) - h2, e := newETHHeader(&types2.Header{ - Number: big.NewInt(int64(limit)), - }) - ts.Require().NoError(e) - return &Header{ - Headers: []*ETHHeader{h1, h2}, - }, nil - } - headerFn := func(_ context.Context, height uint64) (*types2.Header, error) { - extra := common.Hex2Bytes("d88301020a846765746888676f312e32302e35856c696e7578000000b19df4a2150bac492386862ad3df4b666bc096b0505bb694dab0bec348681af766751cb839576e9c515a09c8bffa30a46296ccc56612490eb480d03bf948e10005bbcc0421f90b3d4e2465176c461afb316ebc773c61faee85a6515daa8a923564c6ffd37fb2fe9f118ef88092e8762c7addb526ab7eb1e772baef85181f892c731be0c1891a50e6b06262c816295e26495cef6f69dfa69911d9d8e4f3bbadb89b977cf58294f7239d515e15b24cfeb82494056cf691eaf729b165f32c9757c429dba5051155903067e56ebe3698678e9135ebb5849518aff370ca25e19e1072cc1a9fabcaa7f3e2c0b4b16ad183c473bafe30a36e39fa4a143657e229cd23c77f8fbc8e4e4e241695dd3d248d1e51521eee6619143f349bbafec1551819b8be1efea2fc46ca749aa184248a459464eec1a21e7fc7b71a053d9644e9bb8da4853b8f872cd7c1d6b324bf1922829830646ceadfb658d3de009a61dd481a114a2e761c554b641742c973867899d38a80967d39e406a0a9642d41e9007a27fc1150a267d143a9f786cd2b5eecbdcc4036273705225b956d5e2f8f5eb95d2569c77a677c40c7fbea129d4b171a39b7a8ddabfab2317f59d86abfaf690850223d90e9e7593d91a29331dfc2f84d5adecc75fc39ecab4632c1b4400a3dd1e1298835bcca70f657164e5b75689b64b7fd1fa275f334f28e1896a26afa1295da81418593bd12814463d9f6e45c36a0e47eb4cd3e5b6af29c41e2a3a5636430155a466e216585af3ba772b61c6014342d914470ec7ac2975be345796c2b81db0422a5fd08e40db1fc2368d2245e4b18b1d0b85c921aaaafd2e341760e29fc613edd39f71254614e2055c3287a517ae2f5b9e386cd1b50a4550696d957cb4900f03ab84f83ff2df44193496793b847f64e9d6db1b3953682bb95edd096eb1e69bbd357c200992ca78050d0cbe180cfaa018e8b6c8fd93d6f4cea42bbb345dbc6f0dfdb5bec73a8a257074e82b881cfa06ef3eb4efeca060c2531359abd0eab8af1e3edfa2025fca464ac9c3fd123f6c24a0d78869485a6f79b60359f141df90a0c745125b131caaffd12b772e180fbf38a051c97dabc8aaa0126a233a9e828cdafcc7422c4bb1f4030a56ba364c54103f26bad91508b5220b741b218c5d6af1f979ac42bc68d98a5a0d796c6ab01b659ad0fbd9f515893fdd740b29ba0772dbde9b4635921dd91bd2963a0fc855e31f6338f45b211c4e9dedb7f2eb09de7b4dd66d7c2c7e57f628210187192fb89d4b99dd4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000be807dddb074639cd9fa61b47676c064fc50d62cb1f2c71577def3144fabeb75a8a1c8cb5b51d1d1b4a05eec67988b8685008baa17459ec425dbaebc852f496dc92196cdcc8e6d00c17eb431350c6c50d8b8f05176b90b11b3a3d4feb825ae9702711566df5dbf38e82add4dd1b573b95d2466fa6501ccb81e9d26a352b96150ccbf7b697fd0a419d1d6bf74282782b0b3eb1413c901d6ecf02e8e28939e8fb41b682372335be8070199ad3e8621d1743bcac4cc9d8f0f6e10f41e56461385c8eb5daac804fe3f2bca6ce739d93dbfb27e027f5e9e6da52b9e1c413ce35adc11000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ea0a6e3c511bbd10f4519ece37dc24887e11b55db2d4c6283c44a1c7bd503aaba7666e9f0c830e0ff016c1c750a5e48757a713d0836b1cabfd5c281b1de3b77d1c192183ee226379db83cffc681495730c11fdde79ba4c0cae7bc6faa3f0cc3e6093b633fd7ee4f86970926958d0b7ec80437f936acf212b78f0cd095f4565fff144fd458d233a5bef0274e31810c9df02f98fafde0f841f4e66a1cd000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f8b5830aefffb86097bc63a64e8d730014c39dcaac8f3309e37a11c06f0f5c233b55ba19c1f6c34d2d08de4b030ce825bb21fd884bc0fcb811336857419f5ca42a92ac149a4661a248de10f4ca6496069fdfd10d43bc74ccb81806b6ecd384617d1006b16dead7e4f84c8401dd8eaea0e61c6075d2ab24fcdc423764c21771cac6b241cbff89718f9cc8fc6459b4e7578401dd8eafa010c8358490a494a40c5c92aff8628fa770860a9d34e7fb7df38dfb208b0ddfc380ff15abfc44495e4d4605458bb485f0cac5a152b380a8d0208b3f9ff6216230ec4dd67a73b72b1d17a888c68e111f806ef0b255d012b5185b7420b5fb529c9b9300") - return &types2.Header{ - Number: big.NewInt(int64(height)), - Extra: extra, - }, nil - } - hs, err := setupNonNeighboringEpochHeader(headerFn, nonNeighboringEpochFn, epochHeight, trustedEpochHeight, clienttypes.NewHeight(0, 1000000)) - ts.Require().NoError(err) - target, err := hs.(*Header).Target() - ts.Require().NoError(err) - last, err := hs.(*Header).Last() - ts.Require().NoError(err) - - // checkpoint - ts.Require().Equal(21, len(hs.(*Header).CurrentValidators)) - ts.Require().Equal(int64(611), target.Number.Int64()) - // next checkpoint - ts.Require().Equal(int64(810), last.Number.Int64()) -} - -func (ts *SetupTestSuite) TestSuccess_setupNonNeighboringEpochHeader_containTrusted_notFinalized() { - - epochHeight := uint64(600) - trustedEpochHeight := uint64(200) - - nonNeighboringEpochFn := func(height uint64, limit uint64, checkpoint uint64) (core.Header, error) { - return nil, nil - } - headerFn := func(_ context.Context, height uint64) (*types2.Header, error) { - extra := common.Hex2Bytes("d88301020a846765746888676f312e32302e35856c696e7578000000b19df4a2150bac492386862ad3df4b666bc096b0505bb694dab0bec348681af766751cb839576e9c515a09c8bffa30a46296ccc56612490eb480d03bf948e10005bbcc0421f90b3d4e2465176c461afb316ebc773c61faee85a6515daa8a923564c6ffd37fb2fe9f118ef88092e8762c7addb526ab7eb1e772baef85181f892c731be0c1891a50e6b06262c816295e26495cef6f69dfa69911d9d8e4f3bbadb89b977cf58294f7239d515e15b24cfeb82494056cf691eaf729b165f32c9757c429dba5051155903067e56ebe3698678e9135ebb5849518aff370ca25e19e1072cc1a9fabcaa7f3e2c0b4b16ad183c473bafe30a36e39fa4a143657e229cd23c77f8fbc8e4e4e241695dd3d248d1e51521eee6619143f349bbafec1551819b8be1efea2fc46ca749aa184248a459464eec1a21e7fc7b71a053d9644e9bb8da4853b8f872cd7c1d6b324bf1922829830646ceadfb658d3de009a61dd481a114a2e761c554b641742c973867899d38a80967d39e406a0a9642d41e9007a27fc1150a267d143a9f786cd2b5eecbdcc4036273705225b956d5e2f8f5eb95d2569c77a677c40c7fbea129d4b171a39b7a8ddabfab2317f59d86abfaf690850223d90e9e7593d91a29331dfc2f84d5adecc75fc39ecab4632c1b4400a3dd1e1298835bcca70f657164e5b75689b64b7fd1fa275f334f28e1896a26afa1295da81418593bd12814463d9f6e45c36a0e47eb4cd3e5b6af29c41e2a3a5636430155a466e216585af3ba772b61c6014342d914470ec7ac2975be345796c2b81db0422a5fd08e40db1fc2368d2245e4b18b1d0b85c921aaaafd2e341760e29fc613edd39f71254614e2055c3287a517ae2f5b9e386cd1b50a4550696d957cb4900f03ab84f83ff2df44193496793b847f64e9d6db1b3953682bb95edd096eb1e69bbd357c200992ca78050d0cbe180cfaa018e8b6c8fd93d6f4cea42bbb345dbc6f0dfdb5bec73a8a257074e82b881cfa06ef3eb4efeca060c2531359abd0eab8af1e3edfa2025fca464ac9c3fd123f6c24a0d78869485a6f79b60359f141df90a0c745125b131caaffd12b772e180fbf38a051c97dabc8aaa0126a233a9e828cdafcc7422c4bb1f4030a56ba364c54103f26bad91508b5220b741b218c5d6af1f979ac42bc68d98a5a0d796c6ab01b659ad0fbd9f515893fdd740b29ba0772dbde9b4635921dd91bd2963a0fc855e31f6338f45b211c4e9dedb7f2eb09de7b4dd66d7c2c7e57f628210187192fb89d4b99dd4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000be807dddb074639cd9fa61b47676c064fc50d62cb1f2c71577def3144fabeb75a8a1c8cb5b51d1d1b4a05eec67988b8685008baa17459ec425dbaebc852f496dc92196cdcc8e6d00c17eb431350c6c50d8b8f05176b90b11b3a3d4feb825ae9702711566df5dbf38e82add4dd1b573b95d2466fa6501ccb81e9d26a352b96150ccbf7b697fd0a419d1d6bf74282782b0b3eb1413c901d6ecf02e8e28939e8fb41b682372335be8070199ad3e8621d1743bcac4cc9d8f0f6e10f41e56461385c8eb5daac804fe3f2bca6ce739d93dbfb27e027f5e9e6da52b9e1c413ce35adc11000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ea0a6e3c511bbd10f4519ece37dc24887e11b55db2d4c6283c44a1c7bd503aaba7666e9f0c830e0ff016c1c750a5e48757a713d0836b1cabfd5c281b1de3b77d1c192183ee226379db83cffc681495730c11fdde79ba4c0cae7bc6faa3f0cc3e6093b633fd7ee4f86970926958d0b7ec80437f936acf212b78f0cd095f4565fff144fd458d233a5bef0274e31810c9df02f98fafde0f841f4e66a1cd000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f8b5830aefffb86097bc63a64e8d730014c39dcaac8f3309e37a11c06f0f5c233b55ba19c1f6c34d2d08de4b030ce825bb21fd884bc0fcb811336857419f5ca42a92ac149a4661a248de10f4ca6496069fdfd10d43bc74ccb81806b6ecd384617d1006b16dead7e4f84c8401dd8eaea0e61c6075d2ab24fcdc423764c21771cac6b241cbff89718f9cc8fc6459b4e7578401dd8eafa010c8358490a494a40c5c92aff8628fa770860a9d34e7fb7df38dfb208b0ddfc380ff15abfc44495e4d4605458bb485f0cac5a152b380a8d0208b3f9ff6216230ec4dd67a73b72b1d17a888c68e111f806ef0b255d012b5185b7420b5fb529c9b9300") - return &types2.Header{ - Number: big.NewInt(int64(height)), - Extra: extra, - }, nil - } - hs, err := setupNonNeighboringEpochHeader(headerFn, nonNeighboringEpochFn, epochHeight, trustedEpochHeight, clienttypes.NewHeight(0, 1)) - ts.Require().NoError(err) - ts.Require().Nil(hs) -} - -func (ts *SetupTestSuite) TestError_setupNonNeighboringEpochHeader_notContainTrusted() { - - epochHeight := uint64(600) - trustedEpochHeight := uint64(200) - - nonNeighboringEpochFn := func(height uint64, limit uint64, checkpoint uint64) (core.Header, error) { - return nil, nil - } - headerFn := func(_ context.Context, height uint64) (*types2.Header, error) { - extra := common.Hex2Bytes("d88301020a846765746888676f312e32302e35856c696e7578000000b19df4a2150bac492386862ad3df4b666bc096b0505bb694dab0bec348681af766751cb839576e9c515a09c8bffa30a46296ccc56612490eb480d03bf948e10005bbcc0421f90b3d4e2465176c461afb316ebc773c61faee85a6515daa8a923564c6ffd37fb2fe9f118ef88092e8762c7addb526ab7eb1e772baef85181f892c731be0c1891a50e6b06262c816295e26495cef6f69dfa69911d9d8e4f3bbadb89b977cf58294f7239d515e15b24cfeb82494056cf691eaf729b165f32c9757c429dba5051155903067e56ebe3698678e9135ebb5849518aff370ca25e19e1072cc1a9fabcaa7f3e2c0b4b16ad183c473bafe30a36e39fa4a143657e229cd23c77f8fbc8e4e4e241695dd3d248d1e51521eee6619143f349bbafec1551819b8be1efea2fc46ca749aa184248a459464eec1a21e7fc7b71a053d9644e9bb8da4853b8f872cd7c1d6b324bf1922829830646ceadfb658d3de009a61dd481a114a2e761c554b641742c973867899d38a80967d39e406a0a9642d41e9007a27fc1150a267d143a9f786cd2b5eecbdcc4036273705225b956d5e2f8f5eb95d2569c77a677c40c7fbea129d4b171a39b7a8ddabfab2317f59d86abfaf690850223d90e9e7593d91a29331dfc2f84d5adecc75fc39ecab4632c1b4400a3dd1e1298835bcca70f657164e5b75689b64b7fd1fa275f334f28e1896a26afa1295da81418593bd12814463d9f6e45c36a0e47eb4cd3e5b6af29c41e2a3a5636430155a466e216585af3ba772b61c6014342d914470ec7ac2975be345796c2b81db0422a5fd08e40db1fc2368d2245e4b18b1d0b85c921aaaafd2e341760e29fc613edd39f71254614e2055c3287a517ae2f5b9e386cd1b50a4550696d957cb4900f03ab84f83ff2df44193496793b847f64e9d6db1b3953682bb95edd096eb1e69bbd357c200992ca78050d0cbe180cfaa018e8b6c8fd93d6f4cea42bbb345dbc6f0dfdb5bec73a8a257074e82b881cfa06ef3eb4efeca060c2531359abd0eab8af1e3edfa2025fca464ac9c3fd123f6c24a0d78869485a6f79b60359f141df90a0c745125b131caaffd12b772e180fbf38a051c97dabc8aaa0126a233a9e828cdafcc7422c4bb1f4030a56ba364c54103f26bad91508b5220b741b218c5d6af1f979ac42bc68d98a5a0d796c6ab01b659ad0fbd9f515893fdd740b29ba0772dbde9b4635921dd91bd2963a0fc855e31f6338f45b211c4e9dedb7f2eb09de7b4dd66d7c2c7e57f628210187192fb89d4b99dd4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000be807dddb074639cd9fa61b47676c064fc50d62cb1f2c71577def3144fabeb75a8a1c8cb5b51d1d1b4a05eec67988b8685008baa17459ec425dbaebc852f496dc92196cdcc8e6d00c17eb431350c6c50d8b8f05176b90b11b3a3d4feb825ae9702711566df5dbf38e82add4dd1b573b95d2466fa6501ccb81e9d26a352b96150ccbf7b697fd0a419d1d6bf74282782b0b3eb1413c901d6ecf02e8e28939e8fb41b682372335be8070199ad3e8621d1743bcac4cc9d8f0f6e10f41e56461385c8eb5daac804fe3f2bca6ce739d93dbfb27e027f5e9e6da52b9e1c413ce35adc11000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ea0a6e3c511bbd10f4519ece37dc24887e11b55db2d4c6283c44a1c7bd503aaba7666e9f0c830e0ff016c1c750a5e48757a713d0836b1cabfd5c281b1de3b77d1c192183ee226379db83cffc681495730c11fdde79ba4c0cae7bc6faa3f0cc3e6093b633fd7ee4f86970926958d0b7ec80437f936acf212b78f0cd095f4565fff144fd458d233a5bef0274e31810c9df02f98fafde0f841f4e66a1cd000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f8b5830aefffb86097bc63a64e8d730014c39dcaac8f3309e37a11c06f0f5c233b55ba19c1f6c34d2d08de4b030ce825bb21fd884bc0fcb811336857419f5ca42a92ac149a4661a248de10f4ca6496069fdfd10d43bc74ccb81806b6ecd384617d1006b16dead7e4f84c8401dd8eaea0e61c6075d2ab24fcdc423764c21771cac6b241cbff89718f9cc8fc6459b4e7578401dd8eafa010c8358490a494a40c5c92aff8628fa770860a9d34e7fb7df38dfb208b0ddfc380ff15abfc44495e4d4605458bb485f0cac5a152b380a8d0208b3f9ff6216230ec4dd67a73b72b1d17a888c68e111f806ef0b255d012b5185b7420b5fb529c9b9300") - if height == trustedEpochHeight { - // testnet validator (size = 6) - extra = common.Hex2Bytes("d983010306846765746889676f312e32302e3131856c696e7578000053474aa9061284214b9b9c85549ab3d2b972df0deef66ac2c98e82934ca974fdcd97f3309de967d3c9c43fa711a8d673af5d75465844bf8969c8d1948d903748ac7b8b1720fa64e50c35552c16704d214347f29fa77f77da6d75d7c752b742ad4855bae330426b823e742da31f816cc83bc16d69a9134be0cfb4a1d17ec34f1b5b32d5c20440b8536b1e88f0f2980a75ecd1309ea12fa2ed87a8744fbfc9b863d589037a9ace3b590165ea1c0c5ac72bf600b7c88c1e435f41932c1132aae1bfa0bb68e46b96ccb12c3415e4d82af717d8a2959d3f95eae5dc7d70144ce1b73b403b7eb6e0b973c2d38487e58fd6e145491b110080fb14ac915a0411fc78f19e09a399ddee0d20c63a75d8f930f1694544ad2dc01bb71b214cb885500844365e95cd9942c7276e7fd8a2750ec6dded3dcdc2f351782310b0eadc077db59abca0f0cd26776e2e7acb9f3bce40b1fa5221fd1561226c6263cc5ff474cf03cceff28abc65c9cbae594f725c80e12d96c9b86c3400e529bfe184056e257c07940bb664636f689e8d2027c834681f8f878b73445261034e946bb2d901b4b878f8b23fb860a2e980e217c681cb143f623fd5f9f621f6ff6744aef8e8eac63c68750700d0fc90e764516a9eaf069dae86e8f9db5c32037e33b610b88e180abe6c7cb44fe7291bbbf502d4a93b45b19214a6135d5b043c74d9b040969eb8a0ed038f3283173ff84c840231b4dea02c4e09f3cb878f41d53efbb15dcf08cab13455b16b9bbcfc7bd4e35de0a63e17840231b4dfa0c0931c8edab5ab5979a0762d3516367c2f44cecb5070db0ff7a4af46fc5073ee80672779b27abd01b3cff88b18684bbdc4a42009d1c8335e309dde3049c1ab0b0f457f75667781c9380994a6a92bb47c216f986252b2a8e82874307243c15e7f1b01") - } - return &types2.Header{ - Number: big.NewInt(int64(height)), - Extra: extra, - }, nil - } - _, err := setupNonNeighboringEpochHeader(headerFn, nonNeighboringEpochFn, epochHeight, trustedEpochHeight, clienttypes.NewHeight(0, 1000000)) - ts.Require().True(strings.Contains(err.Error(), "invalid untrusted validator set")) + ts.Require().Equal(int64(602), target.Number.Int64()) } diff --git a/module/util.go b/module/util.go index 4f62913..f56351c 100644 --- a/module/util.go +++ b/module/util.go @@ -14,10 +14,6 @@ func getPreviousEpoch(v uint64) uint64 { return (epochCount - 1) * constant.BlocksPerEpoch } -func isEpoch(v uint64) bool { - return v%constant.BlocksPerEpoch == 0 -} - func getCurrentEpoch(v uint64) uint64 { return toEpoch(v) } diff --git a/module/validator_set.go b/module/validator_set.go index a45db1e..ebddaea 100644 --- a/module/validator_set.go +++ b/module/validator_set.go @@ -9,12 +9,8 @@ import ( type Validators [][]byte -func (v Validators) CheckpointValue() uint64 { - return uint64(len(v)/2 + 1) -} - -func (v Validators) Checkpoint(epoch uint64) uint64 { - return epoch + v.CheckpointValue() +func (v Validators) Checkpoint(turnLength uint8) uint64 { + return uint64(len(v)/2+1) * uint64(turnLength) } func (v Validators) Contains(other Validators) bool { @@ -38,22 +34,23 @@ func ceilDiv(x, y int) int { return (x + y - 1) / y } -func queryValidatorSet(fn getHeaderFn, epochBlockNumber uint64) (Validators, error) { +func queryValidatorSetAndTurnLength(fn getHeaderFn, epochBlockNumber uint64) (Validators, uint8, error) { header, err := fn(context.TODO(), epochBlockNumber) if err != nil { - return nil, err + return nil, 1, err } - return extractValidatorSet(header) + return extractValidatorSetAndTurnLength(header) } -func extractValidatorSet(h *types.Header) (Validators, error) { +func extractValidatorSetAndTurnLength(h *types.Header) (Validators, uint8, error) { + const turnLengthLength = 1 extra := h.Extra if len(extra) < extraVanity+extraSeal { - return nil, fmt.Errorf("invalid extra length : %d", h.Number.Uint64()) + return nil, 1, fmt.Errorf("invalid extra length : %d", h.Number.Uint64()) } num := int(extra[extraVanity]) - if num == 0 || len(extra) <= extraVanity+extraSeal+num*validatorBytesLength { - return nil, fmt.Errorf("invalid validator bytes length: %d", h.Number.Uint64()) + if num == 0 || len(extra) <= extraVanity+extraSeal+num*validatorBytesLength+turnLengthLength { + return nil, 1, fmt.Errorf("invalid validator bytes length: %d", h.Number.Uint64()) } start := extraVanity + validatorNumberSize end := start + num*validatorBytesLength @@ -66,6 +63,6 @@ func extractValidatorSet(h *types.Header) (Validators, error) { validatorWithBLS := validators[s:e] validatorSet = append(validatorSet, validatorWithBLS) } - - return validatorSet, nil + turnLength := extra[end] + return validatorSet, turnLength, nil } diff --git a/module/validator_set_test.go b/module/validator_set_test.go index 153d782..0d09b12 100644 --- a/module/validator_set_test.go +++ b/module/validator_set_test.go @@ -3,7 +3,6 @@ package module import ( "context" "errors" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/stretchr/testify/suite" "math/big" @@ -22,21 +21,19 @@ func (ts *ValidatorSetTestSuite) SetupTest() { } func (ts *ValidatorSetTestSuite) TestSuccessExtractValidatorSet() { - testnetHeader := &types.Header{ - // after luban in testnet: - Number: big.NewInt(29835600), - Extra: common.Hex2Bytes("d883010202846765746888676f312e31392e39856c696e7578000000110bea95071284214b9b9c85549ab3d2b972df0deef66ac2c9ab1757500d6f4fdee439b17cf8e43267f94bc759162fb68de676d2fe10cc4cde26dd06be7e345e9cbf4b1dbf86b262bc35552c16704d214347f29fa77f77da6d75d7c752b742ad4855bae330426b823e742da31f816cc83bc16d69a9134be0cfb4a1d17ec34f1b5b32d5c20440b8536b1e88f0f296c5d20b2a975c050e4220be276ace4892f4b41a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000980a75ecd1309ea12fa2ed87a8744fbfc9b863d589037a9ace3b590165ea1c0c5ac72bf600b7c88c1e435f41932c1132aae1bfa0bb68e46b96ccb12c3415e4d82af717d8a2959d3f95eae5dc7d70144ce1b73b403b7eb6e0b973c2d38487e58fd6e145491b110080fb14ac915a0411fc78f19e09a399ddee0d20c63a75d8f930f1694544ad2dc01bb71b214cb885500844365e95cd9942c7276e7fd8a2750ec6dded3dcdc2f351782310b0eadc077db59abca0f0cd26776e2e7acb9f3bce40b1fa5221fd1561226c6263cc5ff474cf03cceff28abc65c9cbae594f725c80e12d96c9b86c3400e529bfe184056e257c07940bb664636f689e8d2027c834681f8f878b73445261034e946bb2d901b4b878f8b27bb860a140cc9c8cc07d4ddf366440d9784efc88743d26af40f8956dd1c3501e560f745910bb14a5ec392f53cf78ddc2d2d69a146af287f7e079c3cbbfd3d446836d9b9397aa9a803b6c6b4f1cfc50baddbe2378cf194da35b9f4a1a32850114f1c5d9f84c8401c7414ea049d2e0876f51ce4693892331f8344a102aad88eb9e9bcfaa247cc9f898d1f8008401c7414fa0cf8d34727ff1d895bb49ca4be60c3b24d98d8afa9ce78644924e4b9aa39df8548022dc981e8703d3ca8b23fc032089667cb631cb28c32731762813bbf9fdb7e7a56b3945d65f2d72402a2abb9fbaf4bf094a3e5a542e175ecc54b426ee366b2ba200"), - } - validators, err := ExtractValidatorSet(testnetHeader) + + block := previousEpochHeader() + validators, turnLength, err := extractValidatorSetAndTurnLength(block) ts.Require().NoError(err) - ts.Require().Len(validators, 7) - 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") + ts.Require().Len(validators, 4) + ts.Require().Equal(turnLength, uint8(1)) + + block = epochHeader() + validators, turnLength, err = extractValidatorSetAndTurnLength(block) + ts.Require().NoError(err) + ts.Require().Len(validators, 4) + ts.Require().Equal(turnLength, uint8(1)) + } func (ts *ValidatorSetTestSuite) TestErrorExtractValidatorSet() { @@ -44,39 +41,57 @@ func (ts *ValidatorSetTestSuite) TestErrorExtractValidatorSet() { Number: big.NewInt(0), Extra: []byte{}, } - _, err := ExtractValidatorSet(testnetHeader) + _, _, err := ExtractValidatorSetAndTurnLength(testnetHeader) ts.Require().Equal(err.Error(), "invalid extra length : 0") testnetHeader.Extra = make([]byte, extraSeal+extraVanity) - _, err = ExtractValidatorSet(testnetHeader) + _, _, err = ExtractValidatorSetAndTurnLength(testnetHeader) ts.Require().Equal(err.Error(), "invalid validator bytes length: 0") } func (ts *ValidatorSetTestSuite) TestSuccessQueryValidatorSet() { fn := func(ctx context.Context, height uint64) (*types.Header, error) { - return &types.Header{ - Number: big.NewInt(0), - Extra: common.Hex2Bytes("d883010202846765746888676f312e31392e39856c696e7578000000110bea95071284214b9b9c85549ab3d2b972df0deef66ac2c9ab1757500d6f4fdee439b17cf8e43267f94bc759162fb68de676d2fe10cc4cde26dd06be7e345e9cbf4b1dbf86b262bc35552c16704d214347f29fa77f77da6d75d7c752b742ad4855bae330426b823e742da31f816cc83bc16d69a9134be0cfb4a1d17ec34f1b5b32d5c20440b8536b1e88f0f296c5d20b2a975c050e4220be276ace4892f4b41a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000980a75ecd1309ea12fa2ed87a8744fbfc9b863d589037a9ace3b590165ea1c0c5ac72bf600b7c88c1e435f41932c1132aae1bfa0bb68e46b96ccb12c3415e4d82af717d8a2959d3f95eae5dc7d70144ce1b73b403b7eb6e0b973c2d38487e58fd6e145491b110080fb14ac915a0411fc78f19e09a399ddee0d20c63a75d8f930f1694544ad2dc01bb71b214cb885500844365e95cd9942c7276e7fd8a2750ec6dded3dcdc2f351782310b0eadc077db59abca0f0cd26776e2e7acb9f3bce40b1fa5221fd1561226c6263cc5ff474cf03cceff28abc65c9cbae594f725c80e12d96c9b86c3400e529bfe184056e257c07940bb664636f689e8d2027c834681f8f878b73445261034e946bb2d901b4b878f8b27bb860a140cc9c8cc07d4ddf366440d9784efc88743d26af40f8956dd1c3501e560f745910bb14a5ec392f53cf78ddc2d2d69a146af287f7e079c3cbbfd3d446836d9b9397aa9a803b6c6b4f1cfc50baddbe2378cf194da35b9f4a1a32850114f1c5d9f84c8401c7414ea049d2e0876f51ce4693892331f8344a102aad88eb9e9bcfaa247cc9f898d1f8008401c7414fa0cf8d34727ff1d895bb49ca4be60c3b24d98d8afa9ce78644924e4b9aa39df8548022dc981e8703d3ca8b23fc032089667cb631cb28c32731762813bbf9fdb7e7a56b3945d65f2d72402a2abb9fbaf4bf094a3e5a542e175ecc54b426ee366b2ba200"), - }, nil + return epochHeader(), nil } - validators, err := QueryValidatorSet(fn, 200) + validators, turnLength, err := QueryValidatorSetAndTurnLength(fn, 400) ts.Require().NoError(err) - ts.Require().Len(validators, 7) + ts.Require().Len(validators, 4) + ts.Require().Equal(turnLength, uint8(1)) } func (ts *ValidatorSetTestSuite) TestErrorQueryValidatorSet() { fn := func(ctx context.Context, height uint64) (*types.Header, error) { return nil, errors.New("error") } - _, err := QueryValidatorSet(fn, 200) + _, _, err := QueryValidatorSetAndTurnLength(fn, 200) ts.Require().Equal(err.Error(), "error") } +func (ts *ValidatorSetTestSuite) TestCheckpoint() { + validator := Validators(make([][]byte, 1)) + ts.Equal(int(validator.Checkpoint(1)), 1) + ts.Equal(int(validator.Checkpoint(3)), 3) + ts.Equal(int(validator.Checkpoint(9)), 9) + + validator = make([][]byte, 5) + ts.Equal(int(validator.Checkpoint(1)), 3) + ts.Equal(int(validator.Checkpoint(3)), 9) + ts.Equal(int(validator.Checkpoint(9)), 27) + + validator = make([][]byte, 8) + ts.Equal(int(validator.Checkpoint(1)), 5) + ts.Equal(int(validator.Checkpoint(3)), 15) + ts.Equal(int(validator.Checkpoint(9)), 45) + + validator = make([][]byte, 21) + ts.Equal(int(validator.Checkpoint(1)), 11) + ts.Equal(int(validator.Checkpoint(3)), 33) + ts.Equal(int(validator.Checkpoint(9)), 99) +} + func (ts *ValidatorSetTestSuite) TestValidator() { trusted := Validators([][]byte{{1}, {2}, {3}, {4}, {5}}) - ts.Equal(trusted.Checkpoint(5), uint64(8)) - ts.True(trusted.Contains([][]byte{{1}, {2}, {3}, {4}, {5}})) ts.True(trusted.Contains([][]byte{{1}, {2}, {3}, {4}, {5}, {10}, {11}, {12}, {13}, {14}})) ts.True(trusted.Contains([][]byte{{1}, {2}, {3}, {4}})) diff --git a/module/vote.go b/module/vote.go index 97faad1..e3530f6 100644 --- a/module/vote.go +++ b/module/vote.go @@ -10,13 +10,14 @@ import ( ) const ( - BLSPublicKeyLength = 48 - BLSSignatureLength = 96 + blsPublicKeyLength = 48 + blsSignatureLength = 96 validatorNumberSize = 1 + turnLengthLength = 1 ) -type BLSPublicKey [BLSPublicKeyLength]byte -type BLSSignature [BLSSignatureLength]byte +type BLSPublicKey [blsPublicKeyLength]byte +type BLSSignature [blsSignatureLength]byte type ValidatorsBitSet uint64 type VoteAttestation struct { @@ -33,7 +34,6 @@ type VoteData struct { TargetHash common.Hash } -// https://github.com/bnb-chain/bsc/blob/bb6bdc055d1a7f1f049c924028ad8aaf04291b3b/consensus/parlia/parlia.go#L370 func getVoteAttestationFromHeader(header *types.Header) (*VoteAttestation, error) { if len(header.Extra) <= extraVanity+extraSeal { return nil, nil @@ -48,6 +48,7 @@ func getVoteAttestationFromHeader(header *types.Header) (*VoteAttestation, error return nil, nil } start := extraVanity + validatorNumberSize + num*validatorBytesLength + start += turnLengthLength end := len(header.Extra) - extraSeal attestationBytes = header.Extra[start:end] } diff --git a/module/vote_test.go b/module/vote_test.go index f6414d4..47f18c6 100644 --- a/module/vote_test.go +++ b/module/vote_test.go @@ -4,7 +4,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/stretchr/testify/suite" - "math/big" "testing" ) @@ -20,33 +19,29 @@ func (ts *VoteTestSuite) SetupTest() { } func (ts *VoteTestSuite) TestSuccessGetVoteAttestationFromHeaderEpoch() { - testnetHeader := &types.Header{ - Number: big.NewInt(29835600), - Extra: common.Hex2Bytes("d883010202846765746888676f312e31392e39856c696e7578000000110bea95071284214b9b9c85549ab3d2b972df0deef66ac2c9ab1757500d6f4fdee439b17cf8e43267f94bc759162fb68de676d2fe10cc4cde26dd06be7e345e9cbf4b1dbf86b262bc35552c16704d214347f29fa77f77da6d75d7c752b742ad4855bae330426b823e742da31f816cc83bc16d69a9134be0cfb4a1d17ec34f1b5b32d5c20440b8536b1e88f0f296c5d20b2a975c050e4220be276ace4892f4b41a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000980a75ecd1309ea12fa2ed87a8744fbfc9b863d589037a9ace3b590165ea1c0c5ac72bf600b7c88c1e435f41932c1132aae1bfa0bb68e46b96ccb12c3415e4d82af717d8a2959d3f95eae5dc7d70144ce1b73b403b7eb6e0b973c2d38487e58fd6e145491b110080fb14ac915a0411fc78f19e09a399ddee0d20c63a75d8f930f1694544ad2dc01bb71b214cb885500844365e95cd9942c7276e7fd8a2750ec6dded3dcdc2f351782310b0eadc077db59abca0f0cd26776e2e7acb9f3bce40b1fa5221fd1561226c6263cc5ff474cf03cceff28abc65c9cbae594f725c80e12d96c9b86c3400e529bfe184056e257c07940bb664636f689e8d2027c834681f8f878b73445261034e946bb2d901b4b878f8b27bb860a140cc9c8cc07d4ddf366440d9784efc88743d26af40f8956dd1c3501e560f745910bb14a5ec392f53cf78ddc2d2d69a146af287f7e079c3cbbfd3d446836d9b9397aa9a803b6c6b4f1cfc50baddbe2378cf194da35b9f4a1a32850114f1c5d9f84c8401c7414ea049d2e0876f51ce4693892331f8344a102aad88eb9e9bcfaa247cc9f898d1f8008401c7414fa0cf8d34727ff1d895bb49ca4be60c3b24d98d8afa9ce78644924e4b9aa39df8548022dc981e8703d3ca8b23fc032089667cb631cb28c32731762813bbf9fdb7e7a56b3945d65f2d72402a2abb9fbaf4bf094a3e5a542e175ecc54b426ee366b2ba200"), - } - vote, err := getVoteAttestationFromHeader(testnetHeader) + // 400 + header := epochHeader() + vote, err := getVoteAttestationFromHeader(header) ts.Require().NoError(err) - ts.Require().Equal(vote.VoteAddressSet, uint64(123)) - ts.Require().Equal(vote.Data.SourceHash, common.HexToHash("0x49d2e0876f51ce4693892331f8344a102aad88eb9e9bcfaa247cc9f898d1f800")) - ts.Require().Equal(vote.Data.SourceNumber, uint64(29835598)) - ts.Require().Equal(vote.Data.TargetHash, common.HexToHash("0xcf8d34727ff1d895bb49ca4be60c3b24d98d8afa9ce78644924e4b9aa39df854")) - ts.Require().Equal(vote.Data.TargetNumber, uint64(29835599)) - ts.Require().Equal(common.Bytes2Hex(vote.AggSignature[:]), "a140cc9c8cc07d4ddf366440d9784efc88743d26af40f8956dd1c3501e560f745910bb14a5ec392f53cf78ddc2d2d69a146af287f7e079c3cbbfd3d446836d9b9397aa9a803b6c6b4f1cfc50baddbe2378cf194da35b9f4a1a32850114f1c5d9") + ts.Require().Equal(vote.VoteAddressSet, uint64(15)) + ts.Require().Equal(vote.Data.SourceHash, common.HexToHash("0x709f88597f05218c198818991cf5598c9280db30d5bfe899da9b7a8c963bff6c")) + ts.Require().Equal(vote.Data.SourceNumber, uint64(398)) + ts.Require().Equal(vote.Data.TargetHash, common.HexToHash("0x4ec3c90370deeeab62de72108470bccac75d1abe118a778f01afa7a99c976a5d")) + ts.Require().Equal(vote.Data.TargetNumber, uint64(399)) + ts.Require().Equal(common.Bytes2Hex(vote.AggSignature[:]), "8b6dc552b410a6fa44fa31643850bcb314f1d4edb32c0c79ee3efef5397691f3685d80057d77510a00e77a39e8b2497419053c3b81a8901e85590a20a0a2dad529c82f6c175ec3ebca8a9112415aa94718af673c16c0e90e327e27709666e499") } func (ts *VoteTestSuite) TestSuccessGetVoteAttestationFromHeaderNotEpoch() { - testnetHeader := &types.Header{ - Number: big.NewInt(31835601), - Extra: common.Hex2Bytes("d88301020b846765746888676f312e32302e35856c696e7578000000b19df4a2f8b5831defffb860a44482b16993815ff4903016ce83ef788b455e2c80ba9976e8e55ac6591b9f9965234a0a2c579269bc5e09577977322d07d17bb8d657ac621a1abfadcb35b9c9d4713dbdd3d47fd3cc6dc2475c989aa224fecd083101049ef1adea2718b00e37f84c8401e5c5cfa0be938dfeafe5b932c2dcef0e2bebb1a05f31104a59b49d78b0b7746a483c14648401e5c5d0a03658f0bb6692995a9dd3b72a69ec6e8e1b9af4361718d8a275c2b92d26eeffc28027cb6d065d5a6d8749ca45a185add61b9ce470136898643170f8072513ca45f35d826f02cb2494f857beebdac9ec04196c8b30a65352ef155a28ac6a0057ff1601"), - } - vote, err := getVoteAttestationFromHeader(testnetHeader) + // 401 + header := epochHeaderPlus1() + vote, err := getVoteAttestationFromHeader(header) ts.Require().NoError(err) - ts.Require().Equal(vote.VoteAddressSet, uint64(1961983)) - ts.Require().Equal(vote.Data.SourceHash, common.HexToHash("0xbe938dfeafe5b932c2dcef0e2bebb1a05f31104a59b49d78b0b7746a483c1464")) - ts.Require().Equal(vote.Data.SourceNumber, uint64(31835599)) - ts.Require().Equal(vote.Data.TargetHash, common.HexToHash("0x3658f0bb6692995a9dd3b72a69ec6e8e1b9af4361718d8a275c2b92d26eeffc2")) - ts.Require().Equal(vote.Data.TargetNumber, uint64(31835600)) - ts.Require().Equal(common.Bytes2Hex(vote.AggSignature[:]), "a44482b16993815ff4903016ce83ef788b455e2c80ba9976e8e55ac6591b9f9965234a0a2c579269bc5e09577977322d07d17bb8d657ac621a1abfadcb35b9c9d4713dbdd3d47fd3cc6dc2475c989aa224fecd083101049ef1adea2718b00e37") + ts.Require().Equal(vote.VoteAddressSet, uint64(15)) + ts.Require().Equal(vote.Data.SourceHash, common.HexToHash("0x4ec3c90370deeeab62de72108470bccac75d1abe118a778f01afa7a99c976a5d")) + ts.Require().Equal(vote.Data.SourceNumber, uint64(399)) + ts.Require().Equal(vote.Data.TargetHash, common.HexToHash("0xe256fac4dd62cc71eaefd8d6c24ae5209c0e48f5c0b62bcced06dfa838c2ad31")) + ts.Require().Equal(vote.Data.TargetNumber, uint64(400)) + ts.Require().Equal(common.Bytes2Hex(vote.AggSignature[:]), "9338bf42b6ef715e9c887e1b285e706355c2a993cd227497b447f8aad4b7fa44d18cd895862e1a2b961b78656d620f9c015e777cf9bcb6c50e1db2783818bd91f647f6879f8bd199f266f1166f9241f00f955fb5210e7e89e7678680900d1cc1") } func (ts *VoteTestSuite) TestErrorGetVoteAttestationFromHeader() { diff --git a/proto/ibc/lightclients/parlia/v1/parlia.proto b/proto/ibc/lightclients/parlia/v1/parlia.proto index c7131ae..5c70350 100644 --- a/proto/ibc/lightclients/parlia/v1/parlia.proto +++ b/proto/ibc/lightclients/parlia/v1/parlia.proto @@ -31,6 +31,8 @@ message Header { bytes account_proof = 3; repeated bytes current_validators = 4; repeated bytes previous_validators = 5; + uint32 current_turn_length = 6; + uint32 previous_turn_length = 7; } message ConsensusState { diff --git a/tests/prover_network_test.go b/tests/prover_network_test.go new file mode 100644 index 0000000..f2f6f9b --- /dev/null +++ b/tests/prover_network_test.go @@ -0,0 +1,150 @@ +package tests + +import ( + "context" + "github.com/datachainlab/ethereum-ibc-relay-chain/pkg/relay/ethereum/signers/hd" + "github.com/datachainlab/ibc-parlia-relay/module" + "github.com/hyperledger-labs/yui-relayer/config" + "github.com/hyperledger-labs/yui-relayer/log" + "strings" + "testing" + "time" + + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + "github.com/datachainlab/ethereum-ibc-relay-chain/pkg/relay/ethereum" + "github.com/ethereum/go-ethereum/common" + "github.com/hyperledger-labs/yui-relayer/core" + "github.com/stretchr/testify/suite" +) + +type dstChain struct { + core.Chain +} + +func (d dstChain) GetLatestFinalizedHeader() (latestFinalizedHeader core.Header, err error) { + panic("implement me") +} + +type ProverNetworkTestSuite struct { + suite.Suite + prover *module.Prover + chain module.Chain +} + +func TestProverNetworkTestSuite(t *testing.T) { + suite.Run(t, new(ProverNetworkTestSuite)) +} + +func (ts *ProverNetworkTestSuite) SetupTest() { + err := log.InitLogger("DEBUG", "text", "stdout") + ts.Require().NoError(err) + + chain := ts.makeChain("http://localhost:8545", "ibc1") + + ts.chain = chain + ts.prover = ts.makeProver(ts.chain) +} + +func (ts *ProverNetworkTestSuite) TestQueryLatestFinalizedHeader() { + header, err := ts.prover.GetLatestFinalizedHeader() + ts.Require().NoError(err) + ts.Require().NoError(header.ValidateBasic()) + ts.Require().Len(header.(*module.Header).Headers, 3) + h := header.(*module.Header) + _, err = h.Target() + ts.Require().NoError(err) + ts.Require().True(len(h.PreviousValidators) >= 1) + ts.Require().True(len(h.CurrentValidators) >= 1) + ts.Require().True(len(h.AccountProof) >= 1) + ts.Require().True(h.CurrentTurnLength >= 1 && h.CurrentTurnLength <= 9) + ts.Require().True(h.PreviousTurnLength >= 1 && h.PreviousTurnLength <= 9) +} + +func (ts *ProverNetworkTestSuite) TestSetupHeadersForUpdate() { + dst := dstChain{ + Chain: ts.makeChain("http://localhost:8645", "ibc0"), + } + header, err := ts.prover.GetLatestFinalizedHeader() + ts.Require().NoError(err) + setupDone, err := ts.prover.SetupHeadersForUpdate(dst, header) + ts.Require().NoError(err) + ts.Require().True(len(setupDone) > 0) + for _, h := range setupDone { + ts.Require().Len(h.(*module.Header).Headers, 3) + } +} + +func (ts *ProverNetworkTestSuite) TestSuccessCreateInitialLightClientState() { + s1, s2, err := ts.prover.CreateInitialLightClientState(nil) + ts.Require().NoError(err) + + cs := s1.(*module.ClientState) + ts.Require().Equal(cs.ChainId, uint64(9999)) + ts.Require().Equal(cs.TrustingPeriod, 86400*time.Second) + ts.Require().Equal(cs.MaxClockDrift, 1*time.Second) + ts.Require().False(cs.Frozen) + ts.Require().Equal(common.Bytes2Hex(cs.IbcStoreAddress), strings.ToLower(ts.chain.IBCAddress().String()[2:])) + var commitment [32]byte + ts.Require().Equal(common.Bytes2Hex(cs.IbcCommitmentsSlot), common.Bytes2Hex(commitment[:])) + + header, err := ts.chain.Header(context.Background(), cs.GetLatestHeight().GetRevisionHeight()) + ts.Require().NoError(err) + ts.Require().Equal(cs.GetLatestHeight().GetRevisionHeight(), header.Number.Uint64()) + + cVal, cTurn, err := module.QueryValidatorSetAndTurnLength(ts.chain.Header, module.GetCurrentEpoch(header.Number.Uint64())) + ts.Require().NoError(err) + pVal, pTurn, err := module.QueryValidatorSetAndTurnLength(ts.chain.Header, module.GetPreviousEpoch(header.Number.Uint64())) + ts.Require().NoError(err) + consState := s2.(*module.ConsensusState) + ts.Require().Equal(consState.CurrentValidatorsHash, module.MakeEpochHash(cVal, cTurn)) + ts.Require().Equal(consState.PreviousValidatorsHash, module.MakeEpochHash(pVal, pTurn)) + ts.Require().Equal(consState.Timestamp, header.Time) + storageRoot, err := ts.prover.GetStorageRoot(header) + ts.Require().NoError(err) + ts.Require().Equal(common.BytesToHash(consState.StateRoot), storageRoot) +} + +func (ts *ProverNetworkTestSuite) makeChain(rpcAddr string, ibcChainID string) module.Chain { + signerConfig := &hd.SignerConfig{ + Mnemonic: "math razor capable expose worth grape metal sunset metal sudden usage scheme", + Path: "m/44'/60'/0'/0/0", + } + anySignerConfig, err := codectypes.NewAnyWithValue(signerConfig) + ts.Require().NoError(err) + chain, err := ethereum.NewChain(ethereum.ChainConfig{ + EthChainId: 9999, + IbcAddress: "0x2F5703804E29F4252FA9405B8D357220d11b3bd9", + Signer: anySignerConfig, + RpcAddr: rpcAddr, + }) + ts.Require().NoError(err) + codec := core.MakeCodec() + modules := []config.ModuleI{ethereum.Module{}, module.Module{}, hd.Module{}} + for _, m := range modules { + m.RegisterInterfaces(codec.InterfaceRegistry()) + } + err = chain.Init("", 0, codec, false) + ts.Require().NoError(err) + err = chain.SetRelayInfo(&core.PathEnd{ + ChainID: ibcChainID, + ClientID: "xx-parlia-0", + ConnectionID: "connection-0", + ChannelID: "channel-0", + PortID: "transfer", + Order: "UNORDERED", + }, nil, nil) + ts.Require().NoError(err) + return module.NewChain(chain) +} + +func (ts *ProverNetworkTestSuite) makeProver(chain module.Chain) *module.Prover { + config := module.ProverConfig{ + TrustingPeriod: 86400 * time.Second, + MaxClockDrift: 1 * time.Second, + RefreshThresholdRate: &module.Fraction{ + Numerator: 3, + Denominator: 2, + }, + } + return module.NewProver(chain, &config).(*module.Prover) +} diff --git a/tool/testdata/README.md b/tool/testdata/README.md index daccf4c..71f7505 100644 --- a/tool/testdata/README.md +++ b/tool/testdata/README.md @@ -4,6 +4,9 @@ Set bsc rpc addr. ### Misbehavior ```sh +export BSC_IBC_ADDR=`cat ../../e2e/config/demo/ibc-1.json | jq '.chain.ibc_address'` +export BSC_IBC_ADDR=`echo ${BSC_IBC_ADDR:1:42}` + # src/client.rs test_success_submit_misbehavior go run main.go misbehavior success @@ -14,26 +17,18 @@ go run main.go misbehavior error ### Header ```sh +export BSC_RPC_ADDR="http://localhost:8545" +export BSC_IBC_ADDR=`cat ../../e2e/config/demo/ibc-1.json | jq '.chain.ibc_address'` +export BSC_IBC_ADDR=`echo ${BSC_IBC_ADDR:1:42}` + # src/client.rs test_success_update_client_epoch -export BSC_RPC_ADDR="rpc node" go run main.go update success epoch # src/client.rs test_success_update_client_non_epoch -export BSC_RPC_ADDR="rpc node" go run main.go update success latest -# src/client.rs test_error_update_client -export BSC_RPC_ADDR="rpc node" -go run main.go update error +go run main.go update success specified --num 1000 --diff 0 -# src/header/eth_headers.rs test_success_verify_finalized_including_not_finalized_block -export BSC_RPC_ADDR="rpc node" -go run main.go header success specified --num 31894081 +# src/client.rs test_error_update_state_non_neighboring_epoch +go run main.go update error ``` - -### LCP integration data -```sh -export BSC_RPC_ADDR="rpc node" -go run main.go history mainnet --num 240 -go run main.go history testnet --num 240 -``` \ No newline at end of file diff --git a/tool/testdata/internal/common.go b/tool/testdata/internal/common.go index de79a72..589a427 100644 --- a/tool/testdata/internal/common.go +++ b/tool/testdata/internal/common.go @@ -7,16 +7,13 @@ import ( "github.com/datachainlab/ethereum-ibc-relay-chain/pkg/relay/ethereum/signers/hd" "github.com/datachainlab/ibc-parlia-relay/module" "github.com/spf13/viper" + "os" "time" ) const ( - 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 - mainAndTestNetIbcAddress = "0x151f3951FA218cac426edFe078fA9e5C6dceA500" + hdwMnemonic = "math razor capable expose worth grape metal sunset metal sudden usage scheme" + hdwPath = "m/44'/60'/0'/0/0" ) func createRPCAddr() (string, error) { @@ -45,10 +42,10 @@ func createProver() (*module.Prover, module.Chain, error) { return nil, nil, err } chain, err := ethereum.NewChain(ethereum.ChainConfig{ - EthChainId: 56, + EthChainId: 9999, RpcAddr: rpcAddr, Signer: CreateSignerConfig(), - IbcAddress: mainAndTestNetIbcAddress, + IbcAddress: os.Getenv("BSC_IBC_ADDR"), }) if err != nil { return nil, nil, err diff --git a/tool/testdata/internal/create_client.go b/tool/testdata/internal/create_client.go index 1157297..37aa475 100644 --- a/tool/testdata/internal/create_client.go +++ b/tool/testdata/internal/create_client.go @@ -5,7 +5,6 @@ import ( "github.com/cosmos/gogoproto/proto" "github.com/datachainlab/ibc-parlia-relay/module" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" "github.com/spf13/cobra" "log" ) @@ -42,11 +41,11 @@ func (m *createClientModule) createClientSuccessCmd() *cobra.Command { if err != nil { return err } - currentValidatorSet, err := module.QueryValidatorSet(chain.Header, module.GetCurrentEpoch(cs.GetLatestHeight().GetRevisionHeight())) + currentValidatorSet, currentTurnLength, err := module.QueryValidatorSetAndTurnLength(chain.Header, module.GetCurrentEpoch(cs.GetLatestHeight().GetRevisionHeight())) if err != nil { return err } - previousValidatorSet, err := module.QueryValidatorSet(chain.Header, module.GetPreviousEpoch(cs.GetLatestHeight().GetRevisionHeight())) + previousValidatorSet, previousTurnLength, err := module.QueryValidatorSetAndTurnLength(chain.Header, module.GetPreviousEpoch(cs.GetLatestHeight().GetRevisionHeight())) if err != nil { return err } @@ -54,8 +53,8 @@ func (m *createClientModule) createClientSuccessCmd() *cobra.Command { log.Println("consensusState", common.Bytes2Hex(anyConsState)) log.Println("height", cs.GetLatestHeight().GetRevisionHeight()) log.Println("time", consState.GetTimestamp()) - log.Println("currentValidatorSet", common.BytesToHash(crypto.Keccak256(currentValidatorSet...))) - log.Println("previousValidatorSet", common.Bytes2Hex(crypto.Keccak256(previousValidatorSet...))) + log.Println("currentEpochHash", module.MakeEpochHash(currentValidatorSet, currentTurnLength)) + log.Println("previousEpochHash", module.MakeEpochHash(previousValidatorSet, previousTurnLength)) log.Println("storageRoot", consState.(*module.ConsensusState).StateRoot) return nil diff --git a/tool/testdata/internal/header.go b/tool/testdata/internal/header.go index 7f9d0fe..d63d8c8 100644 --- a/tool/testdata/internal/header.go +++ b/tool/testdata/internal/header.go @@ -1,9 +1,12 @@ package internal import ( - "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" + "context" "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/rlp" + "github.com/pkg/errors" "github.com/spf13/cobra" "log" ) @@ -47,29 +50,28 @@ func (m *headerModule) success() *cobra.Command { } func (m *headerModule) printHeader(chain module.Chain, height uint64) error { - log.Println("printHeader latest=", height) - headers, err := module.QueryFinalizedHeader(chain.Header, height, height+10) + log.Println("printHeader height=", height) + header, err := chain.Header(context.Background(), height) if err != nil { - return err + return errors.WithStack(err) } - header := module.Header{ - Headers: headers, - TrustedHeight: &types.Height{ - RevisionNumber: 0, - RevisionHeight: 0, - }, - PreviousValidators: [][]byte{common.Address{}.Bytes()}, - CurrentValidators: [][]byte{common.Address{}.Bytes()}, + if height%constant.BlocksPerEpoch == 0 { + vals, turnLength, err := module.ExtractValidatorSetAndTurnLength(header) + if err != nil { + return errors.WithStack(err) + } + log.Println("validators = ") + for _, val := range vals { + log.Println(common.Bytes2Hex(val)) + } + log.Println("turnLength = ", turnLength) } - pack, err := types.PackClientMessage(&header) + rlpHeader, err := rlp.EncodeToBytes(header) if err != nil { - return err + return errors.WithStack(err) } - marshal, err := pack.Marshal() - - log.Println("header", common.Bytes2Hex(marshal)) - log.Println(header.GetHeight(), len(header.Headers)) + log.Println("ETHHeader.header=", common.Bytes2Hex(rlpHeader)) return nil } diff --git a/tool/testdata/internal/membership/verify_membership.go b/tool/testdata/internal/membership/verify_membership.go index d991f29..6a01565 100644 --- a/tool/testdata/internal/membership/verify_membership.go +++ b/tool/testdata/internal/membership/verify_membership.go @@ -18,9 +18,7 @@ import ( ) const ( - hdwMnemonic = "math razor capable expose worth grape metal sunset metal sudden usage scheme" - hdwPath = "m/44'/60'/0'/0/0" - ibcAddress = "0x702E40245797c5a2108A566b3CE2Bf14Bc6aF841" + ibcAddress = "0x702E40245797c5a2108A566b3CE2Bf14Bc6aF841" ) type verifyMembershipModule struct { diff --git a/tool/testdata/internal/misbehavior.go b/tool/testdata/internal/misbehavior.go index 7facbf3..f1fc347 100644 --- a/tool/testdata/internal/misbehavior.go +++ b/tool/testdata/internal/misbehavior.go @@ -7,10 +7,10 @@ import ( "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/spf13/cobra" "log" + "os" ) type misbehaviorModule struct { @@ -21,11 +21,11 @@ func (m *misbehaviorModule) success() *cobra.Command { Use: "success", RunE: func(cmd *cobra.Command, args []string) error { chainID := uint64(9999) - targetHeight, header1, err := m.getLocalHeader(chainID, 8645, 0) + targetHeight, header1, err := m.getLocalHeader(chainID, 8645, 0, 1) if err != nil { log.Panic(err) } - _, header2, err := m.getLocalHeader(chainID, 8545, targetHeight) + _, header2, err := m.getLocalHeader(chainID, 8545, targetHeight, 2) if err != nil { log.Panic(err) } @@ -40,11 +40,10 @@ func (m *misbehaviorModule) success() *cobra.Command { pack, _ := types.PackClientMessage(&misbehavior) marshal, _ := pack.Marshal() log.Println("misbehavior", common.Bytes2Hex(marshal)) - log.Println("trustedHeight", header1.TrustedHeight) - log.Println("currentValidatorHash", common.Bytes2Hex(crypto.Keccak256(header1.CurrentValidators...))) - log.Println("previousValidatorHash", common.Bytes2Hex(crypto.Keccak256(header1.PreviousValidators...))) - epochCount := header1.GetHeight().GetRevisionHeight() / constant.BlocksPerEpoch - log.Println("currentEpoch", epochCount*constant.BlocksPerEpoch) + log.Println("h1_height", header1.GetHeight()) + log.Println("h1_trustedHeight", header1.TrustedHeight) + log.Println("h2_height", header2.GetHeight()) + log.Println("h2_trustedHeight", header2.TrustedHeight) return nil }, } @@ -101,8 +100,8 @@ func (m *misbehaviorModule) error() *cobra.Command { log.Println("Invalid block: misbehavior1", common.Bytes2Hex(marshal[0:len(marshal)/2])) log.Println("Invalid block: misbehavior2", common.Bytes2Hex(marshal[len(marshal)/2:])) log.Println("Invalid block: height", header.GetHeight()) - log.Println("Invalid block: current_validator_hash", common.Bytes2Hex(crypto.Keccak256(header.(*module.Header).CurrentValidators...))) - log.Println("Invalid block: previous_validator_hash", common.Bytes2Hex(crypto.Keccak256(header.(*module.Header).PreviousValidators...))) + log.Println("Invalid block: current_validator_hash", common.Bytes2Hex(module.MakeEpochHash(header.(*module.Header).CurrentValidators, uint8(header.(*module.Header).CurrentTurnLength)))) + log.Println("Invalid block: previous_validator_hash", common.Bytes2Hex(module.MakeEpochHash(header.(*module.Header).PreviousValidators, uint8(header.(*module.Header).PreviousTurnLength)))) log.Println("Invalid block: trusted_height", updating[0].(*module.Header).TrustedHeight) epochCount := header.GetHeight().GetRevisionHeight() / constant.BlocksPerEpoch log.Println("Invalid block: currentEpoch", epochCount*constant.BlocksPerEpoch) @@ -111,12 +110,12 @@ func (m *misbehaviorModule) error() *cobra.Command { } } -func (m *misbehaviorModule) getLocalHeader(chainID uint64, port int64, targetHeight uint64) (uint64, *module.Header, error) { +func (m *misbehaviorModule) getLocalHeader(chainID uint64, port int64, targetHeight uint64, trustedDiff uint64) (uint64, *module.Header, error) { chain, err := ethereum.NewChain(ethereum.ChainConfig{ EthChainId: chainID, RpcAddr: fmt.Sprintf("http://localhost:%d", port), Signer: CreateSignerConfig(), - IbcAddress: ibcAddress, + IbcAddress: os.Getenv("BSC_IBC_ADDR"), }) if err != nil { return targetHeight, nil, err @@ -143,7 +142,7 @@ func (m *misbehaviorModule) getLocalHeader(chainID uint64, port int64, targetHei if err != nil { return latest, nil, err } - trustedHeight := types.NewHeight(0, target.Number.Uint64()-5) + trustedHeight := types.NewHeight(0, target.Number.Uint64()-trustedDiff) header.TrustedHeight = &trustedHeight return latest, header, nil } diff --git a/tool/testdata/internal/update_client.go b/tool/testdata/internal/update_client.go index b4b283e..c5461f1 100644 --- a/tool/testdata/internal/update_client.go +++ b/tool/testdata/internal/update_client.go @@ -1,15 +1,14 @@ package internal import ( - "fmt" "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" "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/pkg/errors" "github.com/spf13/cobra" "log" + "os" ) type updateClientModule struct { @@ -26,11 +25,11 @@ func (m *updateClientModule) success() *cobra.Command { RunE: func(cmd *cobra.Command, args []string) error { prover, chain, err := createProver() if err != nil { - return err + return errors.WithStack(err) } latest, err := chain.LatestHeight() if err != nil { - return err + return errors.WithStack(err) } return m.printHeader(prover, chain, latest.GetRevisionHeight()) }, @@ -51,6 +50,48 @@ func (m *updateClientModule) success() *cobra.Command { return m.printHeader(prover, chain, epochCount*constant.BlocksPerEpoch+2) }, }) + var num uint64 + var diff int64 + specified := &cobra.Command{ + Use: "specified", + RunE: func(cmd *cobra.Command, args []string) error { + prover, chain, err := createProver() + if err != nil { + return errors.WithStack(err) + } + currentEpoch := module.GetCurrentEpoch(num) + previousEpoch := module.GetPreviousEpoch(num) + validator, turnLength, err := module.QueryValidatorSetAndTurnLength(chain.Header, previousEpoch) + if err != nil { + return errors.WithStack(err) + } + checkpoint := currentEpoch + validator.Checkpoint(turnLength) + target, err := prover.GetLatestFinalizedHeaderByLatestHeight(uint64(int64(num) + 2 + diff)) + if err != nil { + return errors.WithStack(err) + } + log.Println("checkpoint", checkpoint, "turnLength", turnLength, "target", target.GetHeight()) + headers, err := prover.SetupHeadersForUpdateByLatestHeight(types.NewHeight(0, previousEpoch), target.(*module.Header)) + if err != nil { + return errors.WithStack(err) + } + for _, header := range headers { + pack, err := types.PackClientMessage(header) + if err != nil { + return errors.WithStack(err) + } + marshal, err := pack.Marshal() + if err != nil { + return err + } + log.Println(common.Bytes2Hex(marshal)) + } + return nil + }, + } + specified.Flags().Uint64Var(&num, "num", num, "--num") + specified.Flags().Int64Var(&diff, "diff", diff, "--diff") + cmd.AddCommand(specified) return cmd } @@ -61,48 +102,34 @@ func (m *updateClientModule) error() *cobra.Command { RunE: func(cmd *cobra.Command, args []string) error { prover, chain, err := createProver() if err != nil { - return err + return errors.WithStack(err) } latest, err := chain.LatestHeight() if err != nil { - return err + return errors.WithStack(err) } - header, err := prover.GetLatestFinalizedHeaderByLatestHeight(latest.GetRevisionHeight()) + epoch := module.GetCurrentEpoch(latest.GetRevisionHeight()) + header, err := prover.GetLatestFinalizedHeaderByLatestHeight(epoch + 2) if err != nil { - return err + return errors.WithStack(err) } - target, err := header.(*module.Header).Target() + updating, err := prover.SetupHeadersForUpdateByLatestHeight(types.NewHeight(0, header.GetHeight().GetRevisionNumber()-constant.BlocksPerEpoch), header.(*module.Header)) if err != nil { - return err + return errors.WithStack(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).Headers[0] = &module.ETHHeader{Header: rlpTarget} + + // non neighboring epoch + newTrustedHeight := types.NewHeight(0, header.GetHeight().GetRevisionHeight()-2*constant.BlocksPerEpoch) + updating[0].(*module.Header).TrustedHeight = &newTrustedHeight pack, err := types.PackClientMessage(updating[0]) if err != nil { - return err + return errors.WithStack(err) } marshal, err := pack.Marshal() if err != nil { - return err - } - trustedHeight := header.(*module.Header).TrustedHeight.GetRevisionHeight() - trustedCurrentValidatorSet, err := module.QueryValidatorSet(chain.Header, module.GetCurrentEpoch(trustedHeight)) - if err != nil { - return err - } - trustedPreviousValidatorSet, err := module.QueryValidatorSet(chain.Header, module.GetPreviousEpoch(trustedHeight)) - if err != nil { - return err + return errors.WithStack(err) } log.Println("header", common.Bytes2Hex(marshal)) - log.Println("height", header.GetHeight().GetRevisionHeight()) - log.Println("trustedHeight", trustedHeight) - log.Println("trustedCurrentValidatorHash", common.Bytes2Hex(crypto.Keccak256(trustedCurrentValidatorSet...))) - log.Println("trustedPreviousValidatorHash", common.Bytes2Hex(crypto.Keccak256(trustedPreviousValidatorSet...))) - log.Println("newCurrentValidatorHash", common.Bytes2Hex(crypto.Keccak256(header.(*module.Header).CurrentValidators...))) - log.Println("newPreviousValidatorHash", common.Bytes2Hex(crypto.Keccak256(header.(*module.Header).PreviousValidators...))) return nil }, } @@ -112,20 +139,20 @@ func (m *updateClientModule) printHeader(prover *module.Prover, chain module.Cha log.Println("printHeader latest=", height) iHeader, err := prover.GetLatestFinalizedHeaderByLatestHeight(height) if err != nil { - return err + return errors.WithStack(err) } if err = iHeader.ValidateBasic(); err != nil { - return err + return errors.WithStack(err) } header := iHeader.(*module.Header) target, err := header.Target() if err != nil { - return err + return errors.WithStack(err) } - account, err := header.Account(common.HexToAddress(mainAndTestNetIbcAddress)) + account, err := header.Account(common.HexToAddress(os.Getenv("BSC_IBC_ADDR"))) if err != nil { - return err + return errors.WithStack(err) } // setup @@ -145,11 +172,11 @@ func (m *updateClientModule) printHeader(prover *module.Prover, chain module.Cha } trustedHeight := updating[0].(*module.Header).TrustedHeight.GetRevisionHeight() - trustedCurrentValidatorSet, err := module.QueryValidatorSet(chain.Header, module.GetCurrentEpoch(trustedHeight)) + currentValidatorSetOfTrustedHeight, currentTurnLengthOfTrustedHeight, err := module.QueryValidatorSetAndTurnLength(chain.Header, module.GetCurrentEpoch(trustedHeight)) if err != nil { return err } - trustedPreviousValidatorSet, err := module.QueryValidatorSet(chain.Header, module.GetPreviousEpoch(trustedHeight)) + previousValidatorSetOfTrustedHeight, previousTurnLengthOfTrustedHeight, err := module.QueryValidatorSetAndTurnLength(chain.Header, module.GetPreviousEpoch(trustedHeight)) if err != nil { return err } @@ -157,21 +184,18 @@ func (m *updateClientModule) printHeader(prover *module.Prover, chain module.Cha log.Println("stateRoot", account.Root) log.Println("height", header.GetHeight().GetRevisionHeight()) log.Println("trustedHeight", trustedHeight) - log.Println("trustedCurrentValidatorHash", common.Bytes2Hex(crypto.Keccak256(trustedCurrentValidatorSet...))) - log.Println("trustedPreviousValidatorHash", common.Bytes2Hex(crypto.Keccak256(trustedPreviousValidatorSet...))) + log.Println("currentEpochHashOfTrustedHeight", common.Bytes2Hex(module.MakeEpochHash(currentValidatorSetOfTrustedHeight, currentTurnLengthOfTrustedHeight))) + log.Println("previousEpochHashOfTrustedHeight", common.Bytes2Hex(module.MakeEpochHash(previousValidatorSetOfTrustedHeight, previousTurnLengthOfTrustedHeight))) if target.Number.Uint64()%constant.BlocksPerEpoch == 0 { - newValidators, err := module.ExtractValidatorSet(target) + newValidators, newTurnLength, err := module.ExtractValidatorSetAndTurnLength(target) if err != nil { return err } - if len(newValidators) != mainNetValidatorSize { - return fmt.Errorf("invalid validator size for test") - } - log.Println("newCurrentValidatorHash", common.Bytes2Hex(crypto.Keccak256(newValidators...))) + log.Println("newCurrentEpochHash", common.Bytes2Hex(module.MakeEpochHash(newValidators, newTurnLength))) } else { - log.Println("newCurrentValidatorHash", common.Bytes2Hex(crypto.Keccak256(header.CurrentValidators...))) + log.Println("newCurrentEpochHash", common.Bytes2Hex(module.MakeEpochHash(header.CurrentValidators, uint8(header.CurrentTurnLength)))) } - log.Println("newPreviousValidatorHash", common.Bytes2Hex(crypto.Keccak256(header.PreviousValidators...))) + log.Println("newPreviousEpochHash", common.Bytes2Hex(module.MakeEpochHash(header.PreviousValidators, uint8(header.PreviousTurnLength)))) return nil }