diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fd9b8529..33a54f14 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -54,7 +54,9 @@ jobs: run: | make chain make contracts - sleep 20 + # epoch is 200, 400, 500, 1000 + # must wait for 400 block (1.5sec * 400) + sleep 600 make relayer make test - name: integration-test diff --git a/README.md b/README.md index 131c6f7e..72a07128 100644 --- a/README.md +++ b/README.md @@ -3,8 +3,8 @@ ![CI](https://github.com/datachainlab/ibc-parlia-relay/workflows/CI/badge.svg?branch=main) ## Supported Versions -- [yui-relayer v0.5.3](https://github.com/hyperledger-labs/yui-relayer/releases/tag/v0.5.3) -- [ethereum-ibc-relay-chain v0.3.4](https://github.com/datachainlab/ethereum-ibc-relay-chain/releases/tag/v0.3.4) +- [yui-relayer v0.5.11](https://github.com/hyperledger-labs/yui-relayer/releases/tag/v0.5.11) +- [ethereum-ibc-relay-chain v0.3.16](https://github.com/datachainlab/ethereum-ibc-relay-chain/releases/tag/v0.3.6) ## Setup Relayer @@ -29,14 +29,6 @@ func main() { } ``` -## Change blocks per epoch - -* You can change blocks per epoch by build arguments. -* This is only for local net. -``` -go build -tags dev -ldflags="-X github.com/datachainlab/ibc-parlia-relay/module/constant.blocksPerEpoch=20" -o testrly . -``` - ## Development Generate proto buf with protobuf definition of [parlia-elc](https://github.com/datachainlab/parlia-elc). @@ -48,3 +40,12 @@ cd ibc-parlia-relay make proto-import make proto-gen ``` + +## About ForkSpec + +1. Set HF height as soon as possible +As soon as the HF height is determined, please modify the timestamp in the ForkSpec to the height as soon as possible. +HF height is calculated from timestamp, but the further away from the HF, the longer it takes to calculate. + +2. Limitation of the CreateClient +When the latest HF height is not set it is impossible to create client if the latest finalize header is after latest HF timestamp \ No newline at end of file diff --git a/e2e/Makefile b/e2e/Makefile index 440bf9c8..82b711f9 100644 --- a/e2e/Makefile +++ b/e2e/Makefile @@ -13,8 +13,7 @@ contracts: .PHONY:relayer relayer: rm -rf .testrly - go build -tags dev -ldflags="-X github.com/datachainlab/ibc-parlia-relay/module/constant.blocksPerEpoch=20" -o testrly . - # go build -o testrly . + go build -o testrly . ./testrly config init --home .testrly ./testrly chains add-dir config/demo/ --home .testrly ./testrly paths add ibc0 ibc1 ibc01 --file=config/path.json --home .testrly diff --git a/e2e/chains/bsc/Dockerfile.bootstrap b/e2e/chains/bsc/Dockerfile.bootstrap index b7da3b7f..0eca9543 100644 --- a/e2e/chains/bsc/Dockerfile.bootstrap +++ b/e2e/chains/bsc/Dockerfile.bootstrap @@ -3,8 +3,8 @@ 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/bnb-chain/bsc-genesis-contract -b v1.2.4 /root/genesis \ - && cd /root/genesis && npm ci +RUN git clone https://github.com/bnb-chain/bsc-genesis-contract -b develop /root/genesis \ + && cd /root/genesis && git checkout 44ebc6c17a00bd24db3240141a78091528dcebbb && npm ci RUN cd /root/genesis && /root/.local/bin/poetry install RUN cd /root/genesis && forge install --no-git --no-commit foundry-rs/forge-std@v1.7.3 diff --git a/e2e/chains/bsc/docker-compose.bsc.yml b/e2e/chains/bsc/docker-compose.bsc.yml index c183b876..76a0fe84 100644 --- a/e2e/chains/bsc/docker-compose.bsc.yml +++ b/e2e/chains/bsc/docker-compose.bsc.yml @@ -5,5 +5,5 @@ services: dockerfile: Dockerfile.bsc args: GIT_SOURCE: https://github.com/bnb-chain/bsc - GIT_CHECKOUT_BRANCH: v1.5.5 + GIT_CHECKOUT_BRANCH: v1.5.9 image: bsc-geth:docker-local diff --git a/e2e/chains/bsc/docker-compose.simple.yml b/e2e/chains/bsc/docker-compose.simple.yml index 3efc0a57..649dd689 100644 --- a/e2e/chains/bsc/docker-compose.simple.yml +++ b/e2e/chains/bsc/docker-compose.simple.yml @@ -19,7 +19,6 @@ services: dockerfile: Dockerfile.bootstrap env_file: .env environment: - BLOCKS_PER_EPOCH: 20 INIT_HOLDER_BALANCE: "500000000000000000000" NUMS_OF_VALIDATOR: 5 INIT_NUM_OF_CABINETS: 4 @@ -42,7 +41,6 @@ services: dockerfile: Dockerfile.bootstrap env_file: .env2 environment: - BLOCKS_PER_EPOCH: 20 INIT_HOLDER_BALANCE: "500000000000000000000" NUMS_OF_VALIDATOR: 3 INIT_NUM_OF_CABINETS: 2 diff --git a/e2e/chains/bsc/genesis/contracts/BSCValidatorSet.sol b/e2e/chains/bsc/genesis/contracts/BSCValidatorSet.sol index 2db490ed..314bde66 100644 --- a/e2e/chains/bsc/genesis/contracts/BSCValidatorSet.sol +++ b/e2e/chains/bsc/genesis/contracts/BSCValidatorSet.sol @@ -2,67 +2,42 @@ pragma solidity 0.6.4; pragma experimental ABIEncoderV2; import "./System.sol"; -import "./lib/BytesLib.sol"; -import "./lib/BytesToTypes.sol"; -import "./lib/Memory.sol"; -import "./interface/ILightClient.sol"; -import "./interface/ISlashIndicator.sol"; -import "./interface/ITokenHub.sol"; -import "./interface/IRelayerHub.sol"; -import "./interface/IParamSubscriber.sol"; -import "./interface/IBSCValidatorSet.sol"; -import "./interface/IApplication.sol"; -import "./interface/IStakeHub.sol"; -import "./lib/SafeMath.sol"; -import "./lib/RLPDecode.sol"; -import "./lib/CmnPkg.sol"; - -interface ICrossChain { - function registeredContractChannelMap(address, uint8) external view returns (bool); -} +import "./lib/0.6.x/BytesLib.sol"; +import "./lib/0.6.x/BytesToTypes.sol"; +import "./lib/0.6.x/Memory.sol"; +import "./interface/0.6.x/ISlashIndicator.sol"; +import "./interface/0.6.x/IParamSubscriber.sol"; +import "./interface/0.6.x/IBSCValidatorSet.sol"; +import "./interface/0.6.x/IApplication.sol"; +import "./interface/0.6.x/IStakeHub.sol"; +import "./lib/0.6.x/SafeMath.sol"; +import "./lib/0.6.x/RLPDecode.sol"; contract BSCValidatorSet is IBSCValidatorSet, System, IParamSubscriber, IApplication { using SafeMath for uint256; using RLPDecode for *; - // will not transfer value less than 0.1 BNB for validators - uint256 public constant DUSTY_INCOMING = 1e17; - - uint8 public constant JAIL_MESSAGE_TYPE = 1; - uint8 public constant VALIDATORS_UPDATE_MESSAGE_TYPE = 0; - - // the precision of cross chain value transfer. - uint256 public constant PRECISION = 1e10; - uint256 public constant EXPIRE_TIME_SECOND_GAP = 1000; - uint256 public constant MAX_NUM_OF_VALIDATORS = 100; - bytes public constant INIT_VALIDATORSET_BYTES = hex"f905ec80f905e8f846942a7cdd959bfe8d9487b2a43b33565295a698f7e294b6a7edd747c0554875d3fc531d19ba1497992c5e941ff80f3f7f110ffd8920a3ac38fdef318fe94a3f86048c27395000f846946488aa4d1955ee33403f8ccb1d4de5fb97c7ade294220f003d8bdfaadf52aa1e55ae4cc485e6794875941a87e90e440a39c99aa9cb5cea0ad6a3f0b2407b86048c27395000f846949ef9f4360c606c7ab4db26b016007d3ad0ab86a0946103af86a874b705854033438383c82575f25bc29418e2db06cbff3e3c5f856410a1838649e760175786048c27395000f84694ee01c3b1283aa067c58eab4709f85e99d46de5fe94ee4b9bfb1871c64e2bcabb1dc382dc8b7c4218a29415904ab26ab0e99d70b51c220ccdcccabee6e29786048c27395000f84694685b1ded8013785d6623cc18d214320b6bb6475994a20ef4e5e4e7e36258dbf51f4d905114cb1b34bc9413e39085dc88704f4394d35209a02b1a9520320c86048c27395000f8469478f3adfc719c99674c072166708589033e2d9afe9448a30d5eaa7b64492a160f139e2da2800ec3834e94055838358c29edf4dcc1ba1985ad58aedbb6be2b86048c27395000f84694c2be4ec20253b8642161bc3f444f53679c1f3d479466f50c616d737e60d7ca6311ff0d9c434197898a94d1d678a2506eeaa365056fe565df8bc8659f28b086048c27395000f846942f7be8361c80a4c1e7e9aaf001d0877f1cfde218945f93992ac37f3e61db2ef8a587a436a161fd210b94ecbc4fb1a97861344dad0867ca3cba2b860411f086048c27395000f84694ce2fd7544e0b2cc94692d4a704debef7bcb613289444abc67b4b2fba283c582387f54c9cba7c34bafa948acc2ab395ded08bb75ce85bf0f95ad2abc51ad586048c27395000f84694b8f7166496996a7da21cf1f1b04d9b3e26a3d077946770572763289aac606e4f327c2f6cc1aa3b3e3b94882d745ed97d4422ca8da1c22ec49d880c4c097286048c27395000f846942d4c407bbe49438ed859fe965b140dcf1aab71a9943ad0939e120f33518fbba04631afe7a3ed6327b194b2bbb170ca4e499a2b0f3cc85ebfa6e8c4dfcbea86048c27395000f846946bbad7cf34b5fa511d8e963dbba288b1960e75d694853b0f6c324d1f4e76c8266942337ac1b0af1a229442498946a51ca5924552ead6fc2af08b94fcba648601d1a94a2000f846944430b3230294d12c6ab2aac5c2cd68e80b16b581947b107f4976a252a6939b771202c28e64e03f52d694795811a7f214084116949fc4f53cedbf189eeab28601d1a94a2000f84694ea0a6e3c511bbd10f4519ece37dc24887e11b55d946811ca77acfb221a49393c193f3a22db829fcc8e9464feb7c04830dd9ace164fc5c52b3f5a29e5018a8601d1a94a2000f846947ae2f5b9e386cd1b50a4550696d957cb4900f03a94e83bcc5077e6b873995c24bac871b5ad856047e19464e48d4057a90b233e026c1041e6012ada897fe88601d1a94a2000f8469482012708dafc9e1b880fd083b32182b869be8e09948e5adc73a2d233a1b496ed3115464dd6c7b887509428b383d324bc9a37f4e276190796ba5a8947f5ed8601d1a94a2000f8469422b81f8e175ffde54d797fe11eb03f9e3bf75f1d94a1c3ef7ca38d8ba80cce3bfc53ebd2903ed21658942767f7447f7b9b70313d4147b795414aecea54718601d1a94a2000f8469468bf0b8b6fb4e317a0f9d6f03eaf8ce6675bc60d94675cfe570b7902623f47e7f59c9664b5f5065dcf94d84f0d2e50bcf00f2fc476e1c57f5ca2d57f625b8601d1a94a2000f846948c4d90829ce8f72d0163c1d5cf348a862d5506309485c42a7b34309bee2ed6a235f86d16f059deec5894cc2cedc53f0fa6d376336efb67e43d167169f3b78601d1a94a2000f8469435e7a025f4da968de7e4d7e4004197917f4070f194b1182abaeeb3b4d8eba7e6a4162eac7ace23d57394c4fd0d870da52e73de2dd8ded19fe3d26f43a1138601d1a94a2000f84694d6caa02bbebaebb5d7e581e4b66559e635f805ff94c07335cf083c1c46a487f0325769d88e163b653694efaff03b42e41f953a925fc43720e45fb61a19938601d1a94a2000"; - uint32 public constant ERROR_UNKNOWN_PACKAGE_TYPE = 101; - uint32 public constant ERROR_FAIL_CHECK_VALIDATORS = 102; - uint32 public constant ERROR_LEN_OF_VAL_MISMATCH = 103; - uint32 public constant ERROR_RELAYFEE_TOO_LARGE = 104; - uint256 public constant INIT_NUM_OF_CABINETS = 21; - uint256 public constant EPOCH = 200; /*----------------- state of the contract -----------------*/ Validator[] public currentValidatorSet; - uint256 public expireTimeSecondGap; + uint256 public expireTimeSecondGap; // @dev deprecated uint256 public totalInComing; // key is the `consensusAddress` of `Validator`, // value is the index of the element in `currentValidatorSet`. mapping(address => uint256) public currentValidatorSetMap; - uint256 public numOfJailed; + uint256 public numOfJailed; // @dev deprecated uint256 public constant BLOCK_FEES_RATIO_SCALE = 10000; address public constant BURN_ADDRESS = 0x000000000000000000000000000000000000dEaD; uint256 public constant INIT_BURN_RATIO = 1000; uint256 public burnRatio; - bool public burnRatioInitialized; // deprecated + bool public burnRatioInitialized; // @dev deprecated // BEP-127 Temporary Maintenance uint256 public constant INIT_MAX_NUM_OF_MAINTAINING = 3; @@ -86,14 +61,14 @@ contract BSCValidatorSet is IBSCValidatorSet, System, IParamSubscriber, IApplica uint256 public systemRewardBaseRatio; uint256 public previousHeight; - uint256 public previousBalanceOfSystemReward; // deprecated + uint256 public previousBalanceOfSystemReward; // @dev deprecated bytes[] public previousVoteAddrFullSet; bytes[] public currentVoteAddrFullSet; bool public isSystemRewardIncluded; // BEP-294 BC-fusion - Validator[] private _tmpMigratedValidatorSet; - bytes[] private _tmpMigratedVoteAddrs; + Validator[] private _tmpMigratedValidatorSet; // @dev deprecated + bytes[] private _tmpMigratedVoteAddrs; // @dev deprecated // BEP-341 Validators can produce consecutive blocks uint256 public turnLength; // Consecutive number of blocks a validator receives priority for block production @@ -119,8 +94,7 @@ contract BSCValidatorSet is IBSCValidatorSet, System, IParamSubscriber, IApplica uint256[19] slots; } - /*----------------- cross chain package -----------------*/ - struct IbcValidatorSetPackage { + struct ValidatorSetPackage { uint8 packageType; Validator[] validatorSet; bytes[] voteAddrs; @@ -153,38 +127,38 @@ contract BSCValidatorSet is IBSCValidatorSet, System, IParamSubscriber, IApplica /*----------------- events -----------------*/ event validatorSetUpdated(); - event validatorJailed(address indexed validator); - event validatorEmptyJailed(address indexed validator); - event batchTransfer(uint256 amount); - event batchTransferFailed(uint256 indexed amount, string reason); - event batchTransferLowerFailed(uint256 indexed amount, bytes reason); event systemTransfer(uint256 amount); - event directTransfer(address payable indexed validator, uint256 amount); - event directTransferFail(address payable indexed validator, uint256 amount); event deprecatedDeposit(address indexed validator, uint256 amount); event validatorDeposit(address indexed validator, uint256 amount); event validatorMisdemeanor(address indexed validator, uint256 amount); event validatorFelony(address indexed validator, uint256 amount); - event failReasonWithStr(string message); - event unexpectedPackage(uint8 channelId, bytes msgBytes); event paramChange(string key, bytes value); event feeBurned(uint256 amount); event validatorEnterMaintenance(address indexed validator); event validatorExitMaintenance(address indexed validator); event finalityRewardDeposit(address indexed validator, uint256 amount); event deprecatedFinalityRewardDeposit(address indexed validator, uint256 amount); - event tmpValidatorSetUpdated(uint256 validatorsNum); + + event validatorJailed(address indexed validator); // @dev deprecated + event validatorEmptyJailed(address indexed validator); // @dev deprecated + event batchTransfer(uint256 amount); // @dev deprecated + event batchTransferFailed(uint256 indexed amount, string reason); // @dev deprecated + event batchTransferLowerFailed(uint256 indexed amount, bytes reason); // @dev deprecated + event directTransfer(address payable indexed validator, uint256 amount); // @dev deprecated + event directTransferFail(address payable indexed validator, uint256 amount); // @dev deprecated + event failReasonWithStr(string message); // @dev deprecated + event unexpectedPackage(uint8 channelId, bytes msgBytes); // @dev deprecated + event tmpValidatorSetUpdated(uint256 validatorsNum); // @dev deprecated /*----------------- init -----------------*/ function init() external onlyNotInit { - (IbcValidatorSetPackage memory validatorSetPkg, bool valid) = - decodeValidatorSetSynPackage(INIT_VALIDATORSET_BYTES); + (ValidatorSetPackage memory validatorSetPkg, bool valid) = + decodeValidatorSet(INIT_VALIDATORSET_BYTES); require(valid, "failed to parse init validatorSet"); for (uint256 i; i < validatorSetPkg.validatorSet.length; ++i) { currentValidatorSet.push(validatorSetPkg.validatorSet[i]); currentValidatorSetMap[validatorSetPkg.validatorSet[i].consensusAddress] = i + 1; } - expireTimeSecondGap = EXPIRE_TIME_SECOND_GAP; alreadyInit = true; } @@ -195,49 +169,15 @@ contract BSCValidatorSet is IBSCValidatorSet, System, IParamSubscriber, IApplica uint8, bytes calldata msgBytes ) external override onlyInit onlyCrossChainContract initValidatorExtraSet returns (bytes memory responsePayload) { - (IbcValidatorSetPackage memory validatorSetPackage, bool ok) = decodeValidatorSetSynPackage(msgBytes); - if (!ok) { - return CmnPkg.encodeCommonAckPackage(ERROR_FAIL_DECODE); - } - uint32 resCode; - if (validatorSetPackage.packageType == VALIDATORS_UPDATE_MESSAGE_TYPE) { - resCode = updateValidatorSet(validatorSetPackage.validatorSet, validatorSetPackage.voteAddrs); - } else if (validatorSetPackage.packageType == JAIL_MESSAGE_TYPE) { - if (validatorSetPackage.validatorSet.length != 1) { - emit failReasonWithStr("length of jail validators must be one"); - resCode = ERROR_LEN_OF_VAL_MISMATCH; - } else { - address validator = validatorSetPackage.validatorSet[0].consensusAddress; - uint256 index = currentValidatorSetMap[validator]; - if (index == 0 || currentValidatorSet[index - 1].jailed) { - emit validatorEmptyJailed(validator); - } else { - // felony will failed if the validator is the only one in the validator set - bool success = _felony(validator, index - 1); - if (!success) { - emit validatorEmptyJailed(validator); - } - } - resCode = CODE_OK; - } - } else { - resCode = ERROR_UNKNOWN_PACKAGE_TYPE; - } - if (resCode == CODE_OK) { - return new bytes(0); - } else { - return CmnPkg.encodeCommonAckPackage(resCode); - } + revert("deprecated"); } function handleAckPackage(uint8 channelId, bytes calldata msgBytes) external override onlyCrossChainContract { - // should not happen - emit unexpectedPackage(channelId, msgBytes); + revert("deprecated"); } function handleFailAckPackage(uint8 channelId, bytes calldata msgBytes) external override onlyCrossChainContract { - // should not happen - emit unexpectedPackage(channelId, msgBytes); + revert("deprecated"); } /*----------------- External Functions -----------------*/ @@ -262,35 +202,6 @@ contract BSCValidatorSet is IBSCValidatorSet, System, IParamSubscriber, IApplica }); } - // if staking channel is not closed, store the migrated validator set and return - if ( - ICrossChain(CROSS_CHAIN_CONTRACT_ADDR).registeredContractChannelMap( - VALIDATOR_CONTRACT_ADDR, STAKING_CHANNELID - ) - ) { - uint256 newLength = _validatorSet.length; - uint256 oldLength = _tmpMigratedValidatorSet.length; - if (oldLength > newLength) { - for (uint256 i = newLength; i < oldLength; ++i) { - _tmpMigratedValidatorSet.pop(); - _tmpMigratedVoteAddrs.pop(); - } - } - - for (uint256 i; i < newLength; ++i) { - if (i >= oldLength) { - _tmpMigratedValidatorSet.push(_validatorSet[i]); - _tmpMigratedVoteAddrs.push(_voteAddrs[i]); - } else { - _tmpMigratedValidatorSet[i] = _validatorSet[i]; - _tmpMigratedVoteAddrs[i] = _voteAddrs[i]; - } - } - - emit tmpValidatorSetUpdated(newLength); - return; - } - // step 0: force all maintaining validators to exit `Temporary Maintenance` // - 1. validators exit maintenance // - 2. clear all maintainInfo @@ -315,7 +226,6 @@ contract BSCValidatorSet is IBSCValidatorSet, System, IParamSubscriber, IApplica // step 3: do update validator set state totalInComing = 0; - numOfJailed = 0; if (validatorSetTemp.length != 0) { doUpdateState(validatorSetTemp, voteAddrsTemp); } @@ -387,7 +297,7 @@ contract BSCValidatorSet is IBSCValidatorSet, System, IParamSubscriber, IApplica 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, + // when a slash happens, theres will no rewards in some finalityReward intervals, // it's tolerated because slash happens rarely totalValue = balanceOfSystemReward.sub(MAX_SYSTEM_REWARD_BALANCE); } else { @@ -474,17 +384,19 @@ contract BSCValidatorSet is IBSCValidatorSet, System, IParamSubscriber, IApplica function getMiningValidators() external view override returns (address[] memory, bytes[] memory) { uint256 _maxNumOfWorkingCandidates = maxNumOfWorkingCandidates; uint256 _numOfCabinets = numOfCabinets > 0 ? numOfCabinets : INIT_NUM_OF_CABINETS; + uint256 _shuffleInterval = 200; address[] memory validators = getValidators(); bytes[] memory voteAddrs = getVoteAddresses(validators); if (validators.length <= _numOfCabinets) { return (validators, voteAddrs); } + // 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 epochNumber = block.number / _shuffleInterval; uint256 start = epochNumber % validators.length; uint256 target = start; for (uint i; i<_numOfCabinets; i++) { @@ -616,12 +528,7 @@ contract BSCValidatorSet is IBSCValidatorSet, System, IParamSubscriber, IApplica } function removeTmpMigratedValidator(address validator) external onlyStakeHub { - for (uint256 i; i < _tmpMigratedValidatorSet.length; ++i) { - if (_tmpMigratedValidatorSet[i].consensusAddress == validator) { - _tmpMigratedValidatorSet[i].jailed = true; - break; - } - } + revert("deprecated"); } /*----------------- For Temporary Maintenance -----------------*/ @@ -679,15 +586,7 @@ contract BSCValidatorSet is IBSCValidatorSet, System, IParamSubscriber, IApplica /*----------------- 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" - ); - expireTimeSecondGap = newExpireTimeSecondGap; - } else if (Memory.compareStrings(key, "burnRatio")) { + if (Memory.compareStrings(key, "burnRatio")) { require(value.length == 32, "length of burnRatio mismatch"); uint256 newBurnRatio = BytesToTypes.bytesToUint256(32, value); require( @@ -731,9 +630,12 @@ 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"); + + uint256 maxElectedValidators = IStakeHub(STAKE_HUB_ADDR).maxElectedValidators(); require( - newNumOfCabinets <= MAX_NUM_OF_VALIDATORS, "the numOfCabinets must be less than MAX_NUM_OF_VALIDATORS" + newNumOfCabinets <= maxElectedValidators, "the numOfCabinets must be less than maxElectedValidators" ); + numOfCabinets = newNumOfCabinets; } else if (Memory.compareStrings(key, "systemRewardBaseRatio")) { require(value.length == 32, "length of systemRewardBaseRatio mismatch"); @@ -755,8 +657,8 @@ contract BSCValidatorSet is IBSCValidatorSet, System, IParamSubscriber, IApplica 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" + newTurnLength >= 3 && newTurnLength <= 64 || newTurnLength == 1, + "the turnLength should be in [3,64] or equal to 1" ); turnLength = newTurnLength; } else { @@ -766,177 +668,6 @@ contract BSCValidatorSet is IBSCValidatorSet, System, IParamSubscriber, IApplica } /*----------------- 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 { uint256 n = currentValidatorSet.length; uint256 m = newValidatorSet.length; @@ -1007,19 +738,19 @@ contract BSCValidatorSet is IBSCValidatorSet, System, IParamSubscriber, IApplica } /** - * @dev With each epoch, there will be a partial rotation between cabinets and candidates. Rotation is determined by this function + * @dev With each shuffle interval blocks, 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, + uint256 shuffleNumber, uint256 startIdx, uint256 offset, uint256 limit, uint256 modNumber ) internal pure { for (uint256 i; i < limit; ++i) { - uint256 random = uint256(keccak256(abi.encodePacked(epochNumber, startIdx + i))) % modNumber; + uint256 random = uint256(keccak256(abi.encodePacked(shuffleNumber, startIdx + i))) % modNumber; if ((startIdx + i) != (offset + random)) { address tmpAddr = validators[startIdx + i]; bytes memory tmpBLS = voteAddrs[startIdx + i]; @@ -1308,11 +1039,7 @@ contract BSCValidatorSet is IBSCValidatorSet, System, IParamSubscriber, IApplica isFelony = false; if (slashCount >= felonyThreshold) { _felony(validator, index); - if (IStakeHub(STAKE_HUB_ADDR).consensusToOperator(validator) != address(0)) { - ISlashIndicator(SLASH_CONTRACT_ADDR).downtimeSlash(validator, slashCount, shouldRevert); - } else { - ISlashIndicator(SLASH_CONTRACT_ADDR).sendFelonyPackage(validator); - } + ISlashIndicator(SLASH_CONTRACT_ADDR).downtimeSlash(validator, slashCount, shouldRevert); isFelony = true; } else if (slashCount >= misdemeanorThreshold) { _misdemeanor(validator); @@ -1321,71 +1048,12 @@ contract BSCValidatorSet is IBSCValidatorSet, System, IParamSubscriber, IApplica emit validatorExitMaintenance(validator); } - 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; - } - Validator[] memory mergedValidatorSet = new Validator[](_length); - bytes[] memory mergedVoteAddrSet = new bytes[](_length); - - uint256 i; - uint256 j; - uint256 k; - while ((i < validatorSet1.length || j < validatorSet2.length) && k < _length) { - if (i == validatorSet1.length) { - mergedValidatorSet[k] = validatorSet2[j]; - mergedVoteAddrSet[k] = voteAddrSet2[j]; - ++j; - ++k; - continue; - } - - if (j == validatorSet2.length) { - mergedValidatorSet[k] = validatorSet1[i]; - mergedVoteAddrSet[k] = voteAddrSet1[i]; - ++i; - ++k; - continue; - } - - if (validatorSet1[i].votingPower > validatorSet2[j].votingPower) { - mergedValidatorSet[k] = validatorSet1[i]; - mergedVoteAddrSet[k] = voteAddrSet1[i]; - ++i; - } else if (validatorSet1[i].votingPower < validatorSet2[j].votingPower) { - mergedValidatorSet[k] = validatorSet2[j]; - mergedVoteAddrSet[k] = voteAddrSet2[j]; - ++j; - } else { - if (validatorSet1[i].consensusAddress < validatorSet2[j].consensusAddress) { - mergedValidatorSet[k] = validatorSet1[i]; - mergedVoteAddrSet[k] = voteAddrSet1[i]; - ++i; - } else { - mergedValidatorSet[k] = validatorSet2[j]; - mergedVoteAddrSet[k] = voteAddrSet2[j]; - ++j; - } - } - ++k; - } - - return (mergedValidatorSet, mergedVoteAddrSet); - } - - //rlp encode & decode function - function decodeValidatorSetSynPackage(bytes memory msgBytes) + function decodeValidatorSet(bytes memory msgBytes) internal pure - returns (IbcValidatorSetPackage memory, bool) + returns (ValidatorSetPackage memory, bool) { - IbcValidatorSetPackage memory validatorSetPkg; + ValidatorSetPackage memory validatorSetPkg; RLPDecode.Iterator memory iter = msgBytes.toRLPItem().iterator(); bool success = false; diff --git a/e2e/chains/bsc/genesis/genesis-template.template b/e2e/chains/bsc/genesis/genesis-template.template index ad1c6b4d..5a62f795 100644 --- a/e2e/chains/bsc/genesis/genesis-template.template +++ b/e2e/chains/bsc/genesis/genesis-template.template @@ -35,6 +35,7 @@ "bohrTime": 0, "pascalTime": 0, "pragueTime": 0, + "lorentzTime": 0, "blobSchedule": { "cancun": { "target": 3, @@ -48,8 +49,6 @@ } }, "parlia": { - "period": 3, - "epoch": {{BLOCKS_PER_EPOCH}} } }, "nonce": "0x0", diff --git a/e2e/chains/bsc/genesis/scripts/init_holders.template b/e2e/chains/bsc/genesis/scripts/init_holders.template index 40129091..7e97d8d6 100644 --- a/e2e/chains/bsc/genesis/scripts/init_holders.template +++ b/e2e/chains/bsc/genesis/scripts/init_holders.template @@ -1,7 +1,7 @@ const web3 = require("web3") const addresses = "{{INIT_HOLDER_ADDRESSES}}" -const balance = web3.utils.toBN("{{INIT_HOLDER_BALANCE}}").toString("hex") +const balance = BigInt("{{INIT_HOLDER_BALANCE}}").toString(16) const init_holders = addresses.split(",").map(address => ({ address, balance })); exports = module.exports = init_holders diff --git a/e2e/chains/bsc/scripts/bootstrap.sh b/e2e/chains/bsc/scripts/bootstrap.sh index 094d7ab5..33c86f80 100755 --- a/e2e/chains/bsc/scripts/bootstrap.sh +++ b/e2e/chains/bsc/scripts/bootstrap.sh @@ -35,10 +35,9 @@ function init_validator() { function generate_genesis() { INIT_HOLDER_ADDRESSES=$(ls ${workspace}/init-holders | tr '\n' ',') INIT_HOLDER_ADDRESSES=${INIT_HOLDER_ADDRESSES/%,/} - echo "blocks per epoch = ${BLOCKS_PER_EPOCH}" echo "replace genesis-template.template" - sed "s/{{BLOCKS_PER_EPOCH}}/${BLOCKS_PER_EPOCH}/g" genesis-template.template >genesis-template.json + cp genesis-template.template genesis-template.json echo "replace init_holders.template" sed "s/{{INIT_HOLDER_ADDRESSES}}/${INIT_HOLDER_ADDRESSES}/g" scripts/init_holders.template | sed "s/{{INIT_HOLDER_BALANCE}}/${INIT_HOLDER_BALANCE}/g" >scripts/init_holders.js @@ -49,7 +48,7 @@ function generate_genesis() { echo "replace 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 + cp scripts/generate.py.out scripts/generate.py echo "start generate validators" node scripts/generate-validator.js diff --git a/e2e/config/demo/ibc-0.json b/e2e/config/demo/ibc-0.json index c377b9b0..e6224372 100644 --- a/e2e/config/demo/ibc-0.json +++ b/e2e/config/demo/ibc-0.json @@ -31,6 +31,7 @@ "numerator": 1, "denominator": 2 }, - "refreshBlockDifferenceThreshold": 1000 + "refreshBlockDifferenceThreshold": 1000, + "network": "localnet" } } diff --git a/e2e/config/demo/ibc-1.json b/e2e/config/demo/ibc-1.json index 5a446eb4..8184e650 100644 --- a/e2e/config/demo/ibc-1.json +++ b/e2e/config/demo/ibc-1.json @@ -30,6 +30,7 @@ "refreshThresholdRate": { "numerator": 1, "denominator": 2 - } + }, + "network": "localnet" } } diff --git a/go.mod b/go.mod index e627b34f..bee7d843 100644 --- a/go.mod +++ b/go.mod @@ -10,6 +10,7 @@ require ( github.com/datachainlab/ethereum-ibc-relay-chain v0.3.17 github.com/datachainlab/ibc-hd-signer v0.1.2 github.com/ethereum/go-ethereum v1.15.0 + github.com/holiman/uint256 v1.3.2 github.com/hyperledger-labs/yui-relayer v0.5.11 github.com/spf13/cobra v1.8.1 github.com/stretchr/testify v1.10.0 @@ -132,7 +133,6 @@ require ( github.com/hashicorp/yamux v0.1.1 // indirect github.com/hdevalence/ed25519consensus v0.1.0 // indirect github.com/holiman/bloomfilter/v2 v2.0.3 // indirect - github.com/holiman/uint256 v1.3.2 // indirect github.com/huandu/skiplist v1.2.0 // indirect github.com/iancoleman/strcase v0.3.0 // indirect github.com/improbable-eng/grpc-web v0.15.0 // indirect diff --git a/module/config.go b/module/config.go index 13e87df2..511e8131 100644 --- a/module/config.go +++ b/module/config.go @@ -17,5 +17,8 @@ func (c *ProverConfig) Build(chain core.Chain) (core.Prover, error) { } func (c *ProverConfig) Validate() error { + if GetForkParameters(Network(c.Network)) == nil { + return fmt.Errorf("unknown network: %s", c.Network) + } return nil } diff --git a/module/config.pb.go b/module/config.pb.go index 5763c035..9b36b5ef 100644 --- a/module/config.pb.go +++ b/module/config.pb.go @@ -36,6 +36,8 @@ type ProverConfig struct { // Refresh if the difference between blocks in the chain and ClientState exceeds this value. // If the value is 0, no refresh decision is made. RefreshBlockDifferenceThreshold uint64 `protobuf:"varint,4,opt,name=refresh_block_difference_threshold,json=refreshBlockDifferenceThreshold,proto3" json:"refresh_block_difference_threshold,omitempty"` + // Network name + Network string `protobuf:"bytes,5,opt,name=network,proto3" json:"network,omitempty"` } func (m *ProverConfig) Reset() { *m = ProverConfig{} } @@ -99,6 +101,13 @@ func (m *ProverConfig) GetRefreshBlockDifferenceThreshold() uint64 { return 0 } +func (m *ProverConfig) GetNetwork() string { + if m != nil { + return m.Network + } + return "" +} + type Fraction struct { Numerator uint64 `protobuf:"varint,1,opt,name=numerator,proto3" json:"numerator,omitempty"` Denominator uint64 `protobuf:"varint,2,opt,name=denominator,proto3" json:"denominator,omitempty"` @@ -161,32 +170,33 @@ func init() { } var fileDescriptor_4d00ceb9ab8b08a6 = []byte{ - // 396 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x90, 0xc1, 0xaa, 0xd3, 0x40, - 0x14, 0x86, 0x93, 0x5a, 0xe4, 0x3a, 0x57, 0xbd, 0x10, 0x2e, 0x12, 0x8b, 0xa6, 0xa5, 0x1b, 0x8b, - 0xd0, 0x19, 0xd0, 0x37, 0x68, 0x8b, 0xa0, 0x75, 0x51, 0x82, 0x2b, 0x41, 0xc2, 0x64, 0x32, 0x49, - 0x06, 0x93, 0x39, 0xe1, 0x74, 0x22, 0xf5, 0x2d, 0x5c, 0xfa, 0x48, 0x5d, 0x76, 0x23, 0xb8, 0x52, - 0x69, 0x5f, 0x44, 0x32, 0x49, 0x5a, 0x57, 0x72, 0x57, 0x33, 0x9c, 0xf9, 0xff, 0xef, 0x3f, 0xf3, - 0x93, 0x97, 0x28, 0x0b, 0xfe, 0x55, 0x22, 0xab, 0x10, 0xbe, 0x48, 0xdc, 0xb2, 0x8a, 0x63, 0xa1, - 0x38, 0x13, 0xa0, 0x53, 0x95, 0x75, 0x07, 0xad, 0x10, 0x0c, 0x78, 0xcf, 0x3b, 0x2d, 0xed, 0xb4, - 0xb4, 0xd5, 0xd2, 0x56, 0x34, 0x0a, 0x32, 0x80, 0xac, 0x90, 0xcc, 0x8a, 0xe3, 0x3a, 0x65, 0x49, - 0x8d, 0xdc, 0x28, 0xd0, 0xad, 0x7d, 0x74, 0x9b, 0x41, 0x06, 0xf6, 0xca, 0x9a, 0x5b, 0x3b, 0x9d, - 0xfe, 0x18, 0x90, 0x87, 0x1b, 0xcb, 0x5b, 0x5a, 0x8c, 0xf7, 0x9e, 0xdc, 0x18, 0xac, 0xb7, 0x46, - 0xe9, 0x2c, 0xaa, 0x24, 0x2a, 0x48, 0x7c, 0x77, 0xe2, 0xce, 0xae, 0x5f, 0x3d, 0xa5, 0x6d, 0x00, - 0xed, 0x03, 0xe8, 0xaa, 0x0b, 0x58, 0x5c, 0xed, 0x7f, 0x8d, 0x9d, 0xef, 0xbf, 0xc7, 0x6e, 0xf8, - 0xb8, 0xf7, 0x6e, 0xac, 0xd5, 0x5b, 0x93, 0x9b, 0x92, 0xef, 0x22, 0x51, 0x80, 0xf8, 0x1c, 0x25, - 0xa8, 0x52, 0xe3, 0x0f, 0xee, 0x4e, 0x7b, 0x54, 0xf2, 0xdd, 0xb2, 0xb1, 0xae, 0x1a, 0xa7, 0xf7, - 0x89, 0x3c, 0x41, 0x99, 0xa2, 0xdc, 0xe6, 0x91, 0xc9, 0x9b, 0x03, 0x8a, 0x24, 0x42, 0x6e, 0xa4, - 0x7f, 0xcf, 0x32, 0x5f, 0xd0, 0xff, 0x36, 0x44, 0xdf, 0x20, 0x17, 0x4d, 0x42, 0x78, 0xdb, 0x61, - 0x3e, 0xf4, 0x94, 0x90, 0x1b, 0xe9, 0xad, 0xc9, 0xb4, 0xc7, 0xc7, 0xed, 0xbe, 0x2a, 0x4d, 0x25, - 0x4a, 0x2d, 0xe4, 0x25, 0xcf, 0x1f, 0x4e, 0xdc, 0xd9, 0x30, 0x1c, 0x77, 0xca, 0x85, 0xdd, 0xee, - 0xac, 0x3b, 0x03, 0xa7, 0xef, 0xc8, 0x55, 0x1f, 0xe7, 0x3d, 0x23, 0x0f, 0x74, 0x5d, 0x4a, 0xe4, - 0x06, 0xd0, 0x96, 0x39, 0x0c, 0x2f, 0x03, 0x6f, 0x42, 0xae, 0x13, 0xa9, 0xa1, 0x54, 0xda, 0xbe, - 0x0f, 0xec, 0xfb, 0xbf, 0xa3, 0xc5, 0xdb, 0xfd, 0x31, 0x70, 0x0f, 0xc7, 0xc0, 0xfd, 0x73, 0x0c, - 0xdc, 0x6f, 0xa7, 0xc0, 0x39, 0x9c, 0x02, 0xe7, 0xe7, 0x29, 0x70, 0x3e, 0xb2, 0x4c, 0x99, 0xbc, - 0x8e, 0xa9, 0x80, 0x92, 0x25, 0xdc, 0x70, 0x91, 0x73, 0xa5, 0x0b, 0x1e, 0x33, 0x15, 0x8b, 0x79, - 0xfb, 0xf9, 0xb9, 0xed, 0x84, 0x95, 0x90, 0xd4, 0x85, 0x8c, 0xef, 0xdb, 0xba, 0x5f, 0xff, 0x0d, - 0x00, 0x00, 0xff, 0xff, 0x70, 0xff, 0x73, 0x50, 0x78, 0x02, 0x00, 0x00, + // 416 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x91, 0xd1, 0x6a, 0xd4, 0x40, + 0x14, 0x86, 0x37, 0xeb, 0xaa, 0xed, 0x54, 0x2d, 0x0c, 0x45, 0x62, 0xd1, 0xec, 0xb2, 0x37, 0x2e, + 0x42, 0x67, 0x40, 0xdf, 0x60, 0x5b, 0x04, 0xad, 0x17, 0x25, 0x78, 0x25, 0x48, 0x98, 0x4c, 0x4e, + 0xb2, 0x43, 0x93, 0x39, 0xe1, 0xec, 0x44, 0xeb, 0x5b, 0x78, 0xe9, 0x23, 0xf5, 0xb2, 0x97, 0x5e, + 0xa9, 0xec, 0x3e, 0x80, 0xaf, 0x20, 0x99, 0x24, 0x5d, 0xaf, 0xc4, 0xab, 0x99, 0x9c, 0xf9, 0xff, + 0xef, 0x3f, 0xfc, 0x61, 0x2f, 0x08, 0x4a, 0xf5, 0x05, 0x48, 0xd6, 0x84, 0x9f, 0x80, 0xd6, 0xb2, + 0x56, 0x54, 0x1a, 0x25, 0x35, 0xda, 0xdc, 0x14, 0xfd, 0x21, 0x6a, 0x42, 0x87, 0xfc, 0x59, 0xaf, + 0x15, 0xbd, 0x56, 0x74, 0x5a, 0xd1, 0x89, 0x8e, 0xa3, 0x02, 0xb1, 0x28, 0x41, 0x7a, 0x71, 0xda, + 0xe4, 0x32, 0x6b, 0x48, 0x39, 0x83, 0xb6, 0xb3, 0x1f, 0x1f, 0x15, 0x58, 0xa0, 0xbf, 0xca, 0xf6, + 0xd6, 0x4d, 0xe7, 0xbf, 0xc7, 0xec, 0xc1, 0x85, 0xe7, 0x9d, 0x7a, 0x0c, 0x7f, 0xc7, 0x0e, 0x1d, + 0x35, 0x6b, 0x67, 0x6c, 0x91, 0xd4, 0x40, 0x06, 0xb3, 0x30, 0x98, 0x05, 0x8b, 0x83, 0x97, 0x4f, + 0x44, 0x17, 0x20, 0x86, 0x00, 0x71, 0xd6, 0x07, 0x2c, 0xf7, 0xae, 0x7f, 0x4c, 0x47, 0xdf, 0x7e, + 0x4e, 0x83, 0xf8, 0xd1, 0xe0, 0xbd, 0xf0, 0x56, 0x7e, 0xce, 0x0e, 0x2b, 0x75, 0x95, 0xe8, 0x12, + 0xf5, 0x65, 0x92, 0x91, 0xc9, 0x5d, 0x38, 0xfe, 0x7f, 0xda, 0xc3, 0x4a, 0x5d, 0x9d, 0xb6, 0xd6, + 0xb3, 0xd6, 0xc9, 0x3f, 0xb2, 0xc7, 0x04, 0x39, 0xc1, 0x7a, 0x95, 0xb8, 0x55, 0x7b, 0x60, 0x99, + 0x25, 0xa4, 0x1c, 0x84, 0x77, 0x3c, 0xf3, 0xb9, 0xf8, 0x67, 0x43, 0xe2, 0x35, 0x29, 0xdd, 0x26, + 0xc4, 0x47, 0x3d, 0xe6, 0xfd, 0x40, 0x89, 0x95, 0x03, 0x7e, 0xce, 0xe6, 0x03, 0x3e, 0xed, 0xf6, + 0x35, 0x79, 0x0e, 0x04, 0x56, 0xc3, 0x2e, 0x2f, 0x9c, 0xcc, 0x82, 0xc5, 0x24, 0x9e, 0xf6, 0xca, + 0xa5, 0xdf, 0xee, 0x56, 0x77, 0x0b, 0xe4, 0x21, 0xbb, 0x6f, 0xc1, 0x7d, 0x46, 0xba, 0x0c, 0xef, + 0xce, 0x82, 0xc5, 0x7e, 0x3c, 0x7c, 0xce, 0xdf, 0xb2, 0xbd, 0x61, 0x11, 0xfe, 0x94, 0xed, 0xdb, + 0xa6, 0x02, 0x52, 0x0e, 0xc9, 0xd7, 0x3c, 0x89, 0x77, 0x03, 0x3e, 0x63, 0x07, 0x19, 0x58, 0xac, + 0x8c, 0xf5, 0xef, 0x63, 0xff, 0xfe, 0xf7, 0x68, 0xf9, 0xe6, 0x7a, 0x13, 0x05, 0x37, 0x9b, 0x28, + 0xf8, 0xb5, 0x89, 0x82, 0xaf, 0xdb, 0x68, 0x74, 0xb3, 0x8d, 0x46, 0xdf, 0xb7, 0xd1, 0xe8, 0x83, + 0x2c, 0x8c, 0x5b, 0x35, 0xa9, 0xd0, 0x58, 0xc9, 0x4c, 0x39, 0xa5, 0x57, 0xca, 0xd8, 0x52, 0xa5, + 0xd2, 0xa4, 0xfa, 0xa4, 0xab, 0xe5, 0xc4, 0xb7, 0x25, 0x2b, 0xcc, 0x9a, 0x12, 0xd2, 0x7b, 0xfe, + 0x47, 0xbc, 0xfa, 0x13, 0x00, 0x00, 0xff, 0xff, 0xa3, 0xbf, 0xc9, 0x85, 0x92, 0x02, 0x00, 0x00, } func (m *ProverConfig) Marshal() (dAtA []byte, err error) { @@ -209,6 +219,13 @@ func (m *ProverConfig) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if len(m.Network) > 0 { + i -= len(m.Network) + copy(dAtA[i:], m.Network) + i = encodeVarintConfig(dAtA, i, uint64(len(m.Network))) + i-- + dAtA[i] = 0x2a + } if m.RefreshBlockDifferenceThreshold != 0 { i = encodeVarintConfig(dAtA, i, uint64(m.RefreshBlockDifferenceThreshold)) i-- @@ -306,6 +323,10 @@ func (m *ProverConfig) Size() (n int) { if m.RefreshBlockDifferenceThreshold != 0 { n += 1 + sovConfig(uint64(m.RefreshBlockDifferenceThreshold)) } + l = len(m.Network) + if l > 0 { + n += 1 + l + sovConfig(uint64(l)) + } return n } @@ -480,6 +501,38 @@ func (m *ProverConfig) Unmarshal(dAtA []byte) error { break } } + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Network", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowConfig + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthConfig + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthConfig + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Network = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipConfig(dAtA[iNdEx:]) diff --git a/module/constant/development.go b/module/constant/development.go deleted file mode 100644 index 042841f4..00000000 --- a/module/constant/development.go +++ /dev/null @@ -1,24 +0,0 @@ -//go:build dev - -package constant - -import ( - "log" - "strconv" -) - -// can change by ldflags -var blocksPerEpoch string = "200" - -var BlocksPerEpoch uint64 = 200 - -func init() { - iBlocksPerEpoch, err := strconv.Atoi(blocksPerEpoch) - if err != nil { - panic(err) - } - BlocksPerEpoch = uint64(iBlocksPerEpoch) - if BlocksPerEpoch != 200 { - log.Printf("blocks per epoch = %d", BlocksPerEpoch) - } -} diff --git a/module/constant/production.go b/module/constant/production.go deleted file mode 100644 index a10e2f74..00000000 --- a/module/constant/production.go +++ /dev/null @@ -1,5 +0,0 @@ -//go:build !dev - -package constant - -const BlocksPerEpoch uint64 = 200 diff --git a/module/facade.go b/module/facade.go index ff50225d..21ff7030 100644 --- a/module/facade.go +++ b/module/facade.go @@ -7,15 +7,6 @@ import ( ) // Facade for tool modules - -func GetPreviousEpoch(v uint64) uint64 { - return getPreviousEpoch(v) -} - -func GetCurrentEpoch(v uint64) uint64 { - return getCurrentEpoch(v) -} - func QueryFinalizedHeader(ctx context.Context, fn getHeaderFn, height uint64, limitHeight uint64) ([]*ETHHeader, error) { return queryFinalizedHeader(ctx, fn, height, limitHeight) } diff --git a/module/fork_spec.go b/module/fork_spec.go new file mode 100644 index 00000000..1beafd6f --- /dev/null +++ b/module/fork_spec.go @@ -0,0 +1,245 @@ +package module + +import ( + "context" + "fmt" + "github.com/hyperledger-labs/yui-relayer/log" + "math" + "os" + "strconv" +) + +type Network string + +const ( + Localnet Network = "localnet" + Testnet Network = "testnet" + Mainnet Network = "mainnet" +) + +var localLorentzHF isForkSpec_HeightOrTimestamp = &ForkSpec_Height{Height: 1} + +func init() { + localLorentzHFTimestamp := os.Getenv("LOCAL_LORENTZ_HF_TIMESTAMP") + if localLorentzHFTimestamp != "" { + result, err := strconv.Atoi(localLorentzHFTimestamp) + if err != nil { + panic(err) + } + localLorentzHF = &ForkSpec_Timestamp{Timestamp: uint64(result)} + } +} + +func GetForkParameters(network Network) []*ForkSpec { + switch network { + case Localnet: + return []*ForkSpec{ + // Pascal HF + { + // Must Set Milli timestamp + HeightOrTimestamp: &ForkSpec_Height{Height: 0}, + AdditionalHeaderItemCount: 1, + EpochLength: 200, + MaxTurnLength: 9, + }, + // Lorentz HF + { + // Must Set Milli timestamp + HeightOrTimestamp: localLorentzHF, + AdditionalHeaderItemCount: 1, + EpochLength: 500, + MaxTurnLength: 64, + }, + } + case Testnet: + return []*ForkSpec{ + { + // https://forum.bnbchain.org/t/bnb-chain-upgrades-testnet/934 + HeightOrTimestamp: &ForkSpec_Height{Height: 48576786}, + AdditionalHeaderItemCount: 1, + EpochLength: 200, + MaxTurnLength: 9, + }, + { + HeightOrTimestamp: &ForkSpec_Timestamp{Timestamp: 1744097580 * 1000}, + AdditionalHeaderItemCount: 1, + EpochLength: 500, + MaxTurnLength: 64, + }, + } + case Mainnet: + return []*ForkSpec{ + { + // https://bscscan.com/block/47618307 + // https://github.com/bnb-chain/bsc/releases/tag/v1.5.7 + HeightOrTimestamp: &ForkSpec_Height{Height: 47618307}, + AdditionalHeaderItemCount: 1, + EpochLength: 200, + MaxTurnLength: 9, + }, + { + HeightOrTimestamp: &ForkSpec_Timestamp{Timestamp: math.MaxUint64}, + AdditionalHeaderItemCount: 1, + EpochLength: 500, + MaxTurnLength: 64, + }, + } + } + return nil +} + +type BoundaryEpochs struct { + PreviousForkSpec ForkSpec + CurrentForkSpec ForkSpec + BoundaryHeight uint64 + PrevLast uint64 + CurrentFirst uint64 + Intermediates []uint64 +} + +type BoundaryHeight struct { + Height uint64 + CurrentForkSpec ForkSpec +} + +func (b BoundaryHeight) GetBoundaryEpochs(prevForkSpec ForkSpec) (*BoundaryEpochs, error) { + boundaryHeight := b.Height + prevLast := boundaryHeight - (boundaryHeight % prevForkSpec.EpochLength) + index := uint64(0) + currentFirst := uint64(0) + for { + candidate := boundaryHeight + index + if candidate%b.CurrentForkSpec.EpochLength == 0 { + currentFirst = candidate + break + } + index++ + } + intermediates := make([]uint64, 0) + // starts 0, 200, 400...epoch_length + if prevLast == 0 { + const defaultEpochLength = 200 + for mid := prevLast + defaultEpochLength; mid < prevForkSpec.EpochLength; mid += defaultEpochLength { + intermediates = append(intermediates, mid) + } + } + for mid := prevLast + prevForkSpec.EpochLength; mid < currentFirst; mid += prevForkSpec.EpochLength { + intermediates = append(intermediates, mid) + } + + return &BoundaryEpochs{ + PreviousForkSpec: prevForkSpec, + CurrentForkSpec: b.CurrentForkSpec, + BoundaryHeight: boundaryHeight, + PrevLast: prevLast, + CurrentFirst: currentFirst, + Intermediates: intermediates, + }, nil +} + +func (be BoundaryEpochs) CurrentEpochBlockNumber(number uint64) uint64 { + if number >= be.CurrentFirst { + return number - (number % be.CurrentForkSpec.EpochLength) + } + + if len(be.Intermediates) > 0 { + for i := len(be.Intermediates) - 1; i >= 0; i-- { + if number >= be.Intermediates[i] { + return be.Intermediates[i] + } + } + } + return number - (number % be.PreviousForkSpec.EpochLength) +} + +func (be BoundaryEpochs) PreviousEpochBlockNumber(currentEpochBlockNumber uint64) uint64 { + if currentEpochBlockNumber == 0 { + return 0 + } + if currentEpochBlockNumber <= be.PrevLast { + return currentEpochBlockNumber - be.PreviousForkSpec.EpochLength + } + + for i, mid := range be.Intermediates { + if currentEpochBlockNumber == mid { + if i == 0 { + return be.PrevLast + } + return be.Intermediates[i-1] + } + } + + if currentEpochBlockNumber == be.CurrentFirst { + if len(be.Intermediates) == 0 { + return be.PrevLast + } + return be.Intermediates[len(be.Intermediates)-1] + } + + return currentEpochBlockNumber - be.CurrentForkSpec.EpochLength +} + +func FindTargetForkSpec(forkSpecs []*ForkSpec, height uint64, timestamp uint64) (*ForkSpec, *ForkSpec, error) { + reversed := make([]*ForkSpec, len(forkSpecs)) + for i, spec := range forkSpecs { + reversed[len(forkSpecs)-i-1] = spec + } + + getPrev := func(current *ForkSpec, i int) *ForkSpec { + if i == len(reversed)-1 { + return current + } + return reversed[i+1] + } + + for i, spec := range reversed { + if x, ok := spec.GetHeightOrTimestamp().(*ForkSpec_Height); ok { + if x.Height <= height { + return spec, getPrev(spec, i), nil + } + } else { + if spec.GetTimestamp() <= timestamp { + return spec, getPrev(spec, i), nil + } + } + } + return nil, nil, fmt.Errorf("no fork spec found height=%d, timestmp=%d", height, timestamp) +} + +var boundaryHeightCache = make(map[uint64]uint64) + +func GetBoundaryHeight(headerFn getHeaderFn, currentHeight uint64, currentForkSpec ForkSpec) (*BoundaryHeight, error) { + logger := log.GetLogger() + boundaryHeight := uint64(0) + if condition, ok := currentForkSpec.GetHeightOrTimestamp().(*ForkSpec_Height); ok { + boundaryHeight = condition.Height + } else { + ts := currentForkSpec.GetTimestamp() + if v, ok := boundaryHeightCache[ts]; ok { + boundaryHeight = v + } else { + logger.Debug("seek fork height", "currentHeight", currentHeight, "ts", ts) + for i := int64(currentHeight); i >= 0; i-- { + h, err := headerFn(context.Background(), uint64(i)) + if err != nil { + return nil, err + } + if MilliTimestamp(h) == ts { + boundaryHeight = h.Number.Uint64() + logger.Debug("seek fork height found", "currentHeight", currentHeight, "ts", ts, "boundaryHeight", boundaryHeight) + boundaryHeightCache[ts] = boundaryHeight + break + } else if MilliTimestamp(h) < ts { + boundaryHeight = h.Number.Uint64() + 1 + logger.Debug("seek fork height found", "currentHeight", currentHeight, "ts", ts, "boundaryHeight", boundaryHeight) + boundaryHeightCache[ts] = boundaryHeight + break + } + } + } + } + return &BoundaryHeight{ + Height: boundaryHeight, + CurrentForkSpec: currentForkSpec, + }, nil +} diff --git a/module/fork_spec_test.go b/module/fork_spec_test.go new file mode 100644 index 00000000..6fee38ed --- /dev/null +++ b/module/fork_spec_test.go @@ -0,0 +1,309 @@ +package module + +import ( + "context" + "fmt" + "github.com/ethereum/go-ethereum/core/types" + "github.com/hyperledger-labs/yui-relayer/log" + "github.com/stretchr/testify/suite" + "math/big" + "testing" +) + +type ForkSpecTestSuite struct { + suite.Suite +} + +func TestForkSpecTestSuite(t *testing.T) { + suite.Run(t, new(ForkSpecTestSuite)) +} + +func (ts *ForkSpecTestSuite) SetupTest() { + _ = log.InitLogger("DEBUG", "text", "stdout") + boundaryHeightCache = make(map[uint64]uint64) +} + +func (ts *ForkSpecTestSuite) Test_FindTargetForkSpec_ValidHeight() { + forkSpecs := []*ForkSpec{ + {HeightOrTimestamp: &ForkSpec_Height{Height: 100}}, + {HeightOrTimestamp: &ForkSpec_Height{Height: 200}}, + } + height := uint64(150) + timestamp := uint64(0) + + current, previous, err := FindTargetForkSpec(forkSpecs, height, timestamp) + + ts.NoError(err) + ts.Equal(forkSpecs[0], current) + ts.Equal(forkSpecs[0], previous) +} + +func (ts *ForkSpecTestSuite) Test_FindTargetForkSpec_ValidHeight2() { + forkSpecs := []*ForkSpec{ + {HeightOrTimestamp: &ForkSpec_Height{Height: 100}}, + {HeightOrTimestamp: &ForkSpec_Height{Height: 200}}, + } + height := uint64(200) + timestamp := uint64(0) + + current, previous, err := FindTargetForkSpec(forkSpecs, height, timestamp) + + ts.NoError(err) + ts.Equal(forkSpecs[1], current) + ts.Equal(forkSpecs[0], previous) +} + +func (ts *ForkSpecTestSuite) Test_FindTargetForkSpec_ValidTimestamp() { + forkSpecs := []*ForkSpec{ + {HeightOrTimestamp: &ForkSpec_Timestamp{Timestamp: 1000}}, + {HeightOrTimestamp: &ForkSpec_Timestamp{Timestamp: 2000}}, + } + height := uint64(0) + timestamp := uint64(1500) + + current, previous, err := FindTargetForkSpec(forkSpecs, height, timestamp) + + ts.NoError(err) + ts.Equal(forkSpecs[0], current) + ts.Equal(forkSpecs[0], previous) +} + +func (ts *ForkSpecTestSuite) Test_FindTargetForkSpec_ValidTimestamp2() { + forkSpecs := []*ForkSpec{ + {HeightOrTimestamp: &ForkSpec_Timestamp{Timestamp: 1000}}, + {HeightOrTimestamp: &ForkSpec_Timestamp{Timestamp: 2000}}, + } + height := uint64(0) + timestamp := uint64(2000) + + current, previous, err := FindTargetForkSpec(forkSpecs, height, timestamp) + + ts.NoError(err) + ts.Equal(forkSpecs[1], current) + ts.Equal(forkSpecs[0], previous) +} + +func (ts *ForkSpecTestSuite) Test_FindTargetForkSpec_NoMatch() { + forkSpecs := []*ForkSpec{ + {HeightOrTimestamp: &ForkSpec_Height{Height: 100}}, + {HeightOrTimestamp: &ForkSpec_Height{Height: 200}}, + } + height := uint64(50) + timestamp := uint64(0) + + current, previous, err := FindTargetForkSpec(forkSpecs, height, timestamp) + + ts.Error(err) + ts.Nil(current) + ts.Nil(previous) +} + +func (ts *ForkSpecTestSuite) Test_FindTargetForkSpec_Both() { + forkSpecs := []*ForkSpec{ + {HeightOrTimestamp: &ForkSpec_Height{Height: 100}}, + {HeightOrTimestamp: &ForkSpec_Timestamp{Timestamp: 200}}, + } + height := uint64(50) + timestamp := uint64(200) + + current, previous, err := FindTargetForkSpec(forkSpecs, height, timestamp) + + ts.NoError(err) + ts.Equal(forkSpecs[1], current) + ts.Equal(forkSpecs[0], previous) +} + +func (ts *ForkSpecTestSuite) Test_FindTargetForkSpec_EmptyForkSpecs() { + forkSpecs := []*ForkSpec{} + height := uint64(100) + timestamp := uint64(1000) + + current, previous, err := FindTargetForkSpec(forkSpecs, height, timestamp) + + ts.Error(err) + ts.Nil(current) + ts.Nil(previous) +} + +func (ts *ForkSpecTestSuite) Test_GetBoundaryHeight_ValidHeight() { + headerFn := func(ctx context.Context, height uint64) (*types.Header, error) { + return &types.Header{Number: big.NewInt(int64(height))}, nil + } + currentHeight := uint64(100) + currentForkSpec := ForkSpec{HeightOrTimestamp: &ForkSpec_Height{Height: 50}} + + boundaryHeight, err := GetBoundaryHeight(headerFn, currentHeight, currentForkSpec) + + ts.NoError(err) + ts.Equal(uint64(50), boundaryHeight.Height) +} + +func (ts *ForkSpecTestSuite) Test_GetBoundaryHeight_ValidTimestamp() { + headerFn := func(ctx context.Context, height uint64) (*types.Header, error) { + return &types.Header{Number: big.NewInt(int64(height)), Time: uint64(1000)}, nil + } + currentHeight := uint64(100) + currentForkSpec := ForkSpec{HeightOrTimestamp: &ForkSpec_Timestamp{Timestamp: 1000 * 1000}} // msec + + boundaryHeight, err := GetBoundaryHeight(headerFn, currentHeight, currentForkSpec) + + ts.NoError(err) + ts.Equal(uint64(100), boundaryHeight.Height) +} + +func (ts *ForkSpecTestSuite) Test_GetBoundaryHeight_ValidTimestampMultiHeader() { + headerFn := func(ctx context.Context, height uint64) (*types.Header, error) { + return &types.Header{Number: big.NewInt(int64(height)), Time: height}, nil + } + currentHeight := uint64(1100) + currentForkSpec := ForkSpec{HeightOrTimestamp: &ForkSpec_Timestamp{Timestamp: 1000_000}} // msec + + boundaryHeight, err := GetBoundaryHeight(headerFn, currentHeight, currentForkSpec) + + ts.NoError(err) + ts.Equal(uint64(1000), boundaryHeight.Height) +} + +func (ts *ForkSpecTestSuite) Test_GetBoundaryHeight_ValidTimestampMultiHeaderNotJust() { + headerFn := func(ctx context.Context, height uint64) (*types.Header, error) { + return &types.Header{Number: big.NewInt(int64(height)), Time: height}, nil + } + currentHeight := uint64(1100) + currentForkSpec := ForkSpec{HeightOrTimestamp: &ForkSpec_Timestamp{Timestamp: 999_999}} // msec + + boundaryHeight, err := GetBoundaryHeight(headerFn, currentHeight, currentForkSpec) + + ts.NoError(err) + ts.Equal(uint64(1000), boundaryHeight.Height) +} + +func (ts *ForkSpecTestSuite) Test_GetBoundaryHeight_TimestampNotFound() { + headerFn := func(ctx context.Context, height uint64) (*types.Header, error) { + return &types.Header{Number: big.NewInt(int64(height)), Time: uint64(500)}, nil + } + currentHeight := uint64(100) + currentForkSpec := ForkSpec{HeightOrTimestamp: &ForkSpec_Timestamp{Timestamp: 1000}} + + boundaryHeight, err := GetBoundaryHeight(headerFn, currentHeight, currentForkSpec) + + ts.NoError(err) + ts.Equal(uint64(0), boundaryHeight.Height) +} + +func (ts *ForkSpecTestSuite) Test_GetBoundaryHeight_HeaderFnError() { + headerFn := func(ctx context.Context, height uint64) (*types.Header, error) { + return nil, fmt.Errorf("header not found") + } + currentHeight := uint64(100) + currentForkSpec := ForkSpec{HeightOrTimestamp: &ForkSpec_Timestamp{Timestamp: 1000}} + + _, err := GetBoundaryHeight(headerFn, currentHeight, currentForkSpec) + + ts.Error(err) +} + +func (ts *ForkSpecTestSuite) Test_Success_GetBoundaryEpochs() { + forkSpecs := []*ForkSpec{ + {HeightOrTimestamp: &ForkSpec_Height{Height: 0}, EpochLength: 200}, + {EpochLength: 500}, + } + epochs, err := BoundaryHeight{Height: 1501, CurrentForkSpec: *forkSpecs[1]}.GetBoundaryEpochs(*forkSpecs[0]) + ts.Require().NoError(err) + ts.Require().Equal(epochs.PrevLast, uint64(1400)) + ts.Require().Equal(epochs.Intermediates, []uint64{1600, 1800}) + ts.Require().Equal(epochs.CurrentFirst, uint64(2000)) + + epochs, err = BoundaryHeight{Height: 1600, CurrentForkSpec: *forkSpecs[1]}.GetBoundaryEpochs(*forkSpecs[0]) + ts.Require().NoError(err) + ts.Require().Equal(epochs.PrevLast, uint64(1600)) + ts.Require().Equal(epochs.Intermediates, []uint64{1800}) + ts.Require().Equal(epochs.CurrentFirst, uint64(2000)) + + epochs, err = BoundaryHeight{Height: 1601, CurrentForkSpec: *forkSpecs[1]}.GetBoundaryEpochs(*forkSpecs[0]) + ts.Require().NoError(err) + ts.Require().Equal(epochs.PrevLast, uint64(1600)) + ts.Require().Equal(epochs.Intermediates, []uint64{1800}) + ts.Require().Equal(epochs.CurrentFirst, uint64(2000)) + + epochs, err = BoundaryHeight{Height: 1800, CurrentForkSpec: *forkSpecs[1]}.GetBoundaryEpochs(*forkSpecs[0]) + ts.Require().NoError(err) + ts.Require().Equal(epochs.PrevLast, uint64(1800)) + ts.Require().Equal(epochs.Intermediates, []uint64{}) + ts.Require().Equal(epochs.CurrentFirst, uint64(2000)) + + epochs, err = BoundaryHeight{Height: 2000, CurrentForkSpec: *forkSpecs[1]}.GetBoundaryEpochs(*forkSpecs[0]) + ts.Require().NoError(err) + ts.Require().Equal(epochs.PrevLast, uint64(2000)) + ts.Require().Equal(epochs.Intermediates, []uint64{}) + ts.Require().Equal(epochs.CurrentFirst, uint64(2000)) +} + +func (ts *ForkSpecTestSuite) Test_Success_GetBoundaryEpochs_After_Lorentz() { + forkSpecs := []*ForkSpec{ + {HeightOrTimestamp: &ForkSpec_Height{Height: 0}, EpochLength: 200}, + {EpochLength: 500}, + } + epochs, err := BoundaryHeight{Height: 1, CurrentForkSpec: *forkSpecs[1]}.GetBoundaryEpochs(*forkSpecs[0]) + ts.Require().NoError(err) + ts.Require().Equal(epochs.PrevLast, uint64(0)) + ts.Require().Equal(epochs.Intermediates, []uint64{200, 400}) + ts.Require().Equal(epochs.CurrentFirst, uint64(500)) + ts.Require().Equal(epochs.CurrentEpochBlockNumber(199), uint64(0)) + ts.Require().Equal(epochs.CurrentEpochBlockNumber(200), uint64(200)) + ts.Require().Equal(epochs.CurrentEpochBlockNumber(399), uint64(200)) + ts.Require().Equal(epochs.CurrentEpochBlockNumber(400), uint64(400)) + ts.Require().Equal(epochs.CurrentEpochBlockNumber(499), uint64(400)) + ts.Require().Equal(epochs.CurrentEpochBlockNumber(500), uint64(500)) + ts.Require().Equal(epochs.CurrentEpochBlockNumber(501), uint64(500)) + ts.Require().Equal(epochs.CurrentEpochBlockNumber(999), uint64(500)) + ts.Require().Equal(epochs.CurrentEpochBlockNumber(1000), uint64(1000)) + ts.Require().Equal(epochs.CurrentEpochBlockNumber(1001), uint64(1000)) + ts.Require().Equal(epochs.CurrentEpochBlockNumber(1499), uint64(1000)) + ts.Require().Equal(epochs.CurrentEpochBlockNumber(1500), uint64(1500)) + ts.Require().Equal(epochs.CurrentEpochBlockNumber(1501), uint64(1500)) + + ts.Require().Equal(epochs.PreviousEpochBlockNumber(0), uint64(0)) + ts.Require().Equal(epochs.PreviousEpochBlockNumber(200), uint64(0)) + ts.Require().Equal(epochs.PreviousEpochBlockNumber(400), uint64(200)) + ts.Require().Equal(epochs.PreviousEpochBlockNumber(500), uint64(400)) + ts.Require().Equal(epochs.PreviousEpochBlockNumber(1000), uint64(500)) + ts.Require().Equal(epochs.PreviousEpochBlockNumber(1500), uint64(1000)) +} + +func (ts *ForkSpecTestSuite) Test_Success_GetBoundaryEpochs_After_Maxwell() { + forkSpecs := []*ForkSpec{ + {HeightOrTimestamp: &ForkSpec_Height{Height: 0}, EpochLength: 500}, + {EpochLength: 1000}, + } + epochs, err := BoundaryHeight{Height: 1, CurrentForkSpec: *forkSpecs[1]}.GetBoundaryEpochs(*forkSpecs[0]) + ts.Require().NoError(err) + ts.Require().Equal(epochs.PrevLast, uint64(0)) + ts.Require().Equal(epochs.Intermediates, []uint64{200, 400, 500}) + ts.Require().Equal(epochs.CurrentFirst, uint64(1000)) + ts.Require().Equal(epochs.CurrentEpochBlockNumber(199), uint64(0)) + ts.Require().Equal(epochs.CurrentEpochBlockNumber(200), uint64(200)) + ts.Require().Equal(epochs.CurrentEpochBlockNumber(399), uint64(200)) + ts.Require().Equal(epochs.CurrentEpochBlockNumber(400), uint64(400)) + ts.Require().Equal(epochs.CurrentEpochBlockNumber(499), uint64(400)) + ts.Require().Equal(epochs.CurrentEpochBlockNumber(500), uint64(500)) + ts.Require().Equal(epochs.CurrentEpochBlockNumber(501), uint64(500)) + ts.Require().Equal(epochs.CurrentEpochBlockNumber(999), uint64(500)) + ts.Require().Equal(epochs.CurrentEpochBlockNumber(1000), uint64(1000)) + ts.Require().Equal(epochs.CurrentEpochBlockNumber(1001), uint64(1000)) + ts.Require().Equal(epochs.CurrentEpochBlockNumber(1499), uint64(1000)) + ts.Require().Equal(epochs.CurrentEpochBlockNumber(1500), uint64(1000)) + ts.Require().Equal(epochs.CurrentEpochBlockNumber(1501), uint64(1000)) + ts.Require().Equal(epochs.CurrentEpochBlockNumber(1999), uint64(1000)) + ts.Require().Equal(epochs.CurrentEpochBlockNumber(2000), uint64(2000)) + ts.Require().Equal(epochs.CurrentEpochBlockNumber(2001), uint64(2000)) + ts.Require().Equal(epochs.CurrentEpochBlockNumber(2999), uint64(2000)) + ts.Require().Equal(epochs.CurrentEpochBlockNumber(3000), uint64(3000)) + + ts.Require().Equal(epochs.PreviousEpochBlockNumber(0), uint64(0)) + ts.Require().Equal(epochs.PreviousEpochBlockNumber(200), uint64(0)) + ts.Require().Equal(epochs.PreviousEpochBlockNumber(400), uint64(200)) + ts.Require().Equal(epochs.PreviousEpochBlockNumber(500), uint64(400)) + ts.Require().Equal(epochs.PreviousEpochBlockNumber(1000), uint64(500)) + ts.Require().Equal(epochs.PreviousEpochBlockNumber(2000), uint64(1000)) + ts.Require().Equal(epochs.PreviousEpochBlockNumber(3000), uint64(2000)) +} diff --git a/module/header.go b/module/header.go index 9498d139..d1c82261 100644 --- a/module/header.go +++ b/module/header.go @@ -2,6 +2,8 @@ package module import ( "fmt" + "github.com/ethereum/go-ethereum/common" + "github.com/holiman/uint256" "log" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" @@ -70,3 +72,11 @@ func (h *Header) Last() (*types.Header, error) { } return decodedHeaders[len(decodedHeaders)-1], nil } + +func MilliTimestamp(h *types.Header) uint64 { + milliseconds := uint64(0) + if h.MixDigest != (common.Hash{}) { + milliseconds = uint256.NewInt(0).SetBytes32(h.MixDigest[:]).Uint64() + } + return h.Time*1000 + milliseconds +} diff --git a/module/header_query_test.go b/module/header_query_test.go index 1c23d224..90530d37 100644 --- a/module/header_query_test.go +++ b/module/header_query_test.go @@ -46,7 +46,7 @@ func (ts *HeaderQueryTestSuite) TestErrorQueryFinalizedHeader() { return &types.Header{Number: big.NewInt(int64(height))}, nil } - headers, err = queryFinalizedHeader(context.Background(), fn, 360, 400) + headers, err = queryFinalizedHeader(context.Background(), fn, 760, 1000) ts.Require().NoError(err) ts.Require().Nil(headers) } @@ -61,9 +61,9 @@ func (ts *HeaderQueryTestSuite) TestSuccessQueryFinalizedHeader() { return &types.Header{Number: big.NewInt(int64(height))}, nil } - headers, err := queryFinalizedHeader(context.Background(), fn, 360, 402) + headers, err := queryFinalizedHeader(context.Background(), fn, 760, 1002) ts.Require().NoError(err) - ts.Require().Len(headers, 402-360) + ts.Require().Len(headers, 1002-760) } func (ts *HeaderQueryTestSuite) TestSuccessQueryLatestFinalizedHeader() { @@ -79,9 +79,9 @@ func (ts *HeaderQueryTestSuite) TestSuccessQueryLatestFinalizedHeader() { height, h, err := queryLatestFinalizedHeader(context.Background(), getHeader, latestBlockNumber) ts.Require().NoError(err) ts.Require().Len(h, 3) - ts.Require().Equal(int(height), 401) + ts.Require().Equal(int(height), 1001) } - for i := 403; i < 403+100; i++ { + for i := 1003; i < 1003+100; i++ { verify(uint64(i)) } } diff --git a/module/lib_test.go b/module/lib_test.go index 572d8e31..e2131704 100644 --- a/module/lib_test.go +++ b/module/lib_test.go @@ -17,36 +17,36 @@ func fromRlp(hex string) *types.Header { } func previousEpochHeader() *types.Header { - return fromRlp("f90391a0844dee9abff97d261ae0049fe38246ac10aba49f2b8618f28f7c2d19e62eccf9a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948fdaaa7e6631e438625ca25c857a3727ea28e565a0ecf1aa30fa754576ac4abc3cf2a61d1babd41c7e5515855efd857b2d3f37866ba00f0ea7d212c4aaca329b03f5e9ed9c69d3641eb5e03a4edb69b61e6f9d8d51efa0c3372a1f332fc4245e1a9fdcb62580fc6dae741087a8029560f19216dd3d58b9b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000281c88402625a00826c7484669a6a91b90173d98301040b846765746889676f312e32312e3132856c696e7578000020155b72048fdaaa7e6631e438625ca25c857a3727ea28e565b94a73be71b4a5703b4d0b36e4f65d52615b668b385efc047f7f385ace378981fa3750a0bc16ca6f8217be599bcfa274b2e42bc54d19116d2348ac83461e2e0915d508ad921ebe99c27c8fdbd30aecdbe86f95aee2e06995f83ebeb327924669629f193ffd3257315c79ed5a4867ec53b502b5e6d9a13701eafb76870cb220843b8c6476824bfa158c66a3f3d2fba1d440da8edc79b59ed9a3a43db62bd7659f7d4e25073f9241dba560600b23e26c30d48ea0395eeeb4ede04db2de85453e0936b441c339a26d10cfa71b50a50dd5edefbafd33740101d074b6d58b56a787a7644ddfff77d0c00f9e62cc58c931e671afc564f3f6e255cc6fc8a567015cbc63c3d778cef5e8dbfdaf1fd8f758a764f2667aad2d3775954e4ac23e726226b66f0a94631bd0b6d937b22955d73eed65a31a6f535662f51cc7547143f6f201a0000000000000000000000000000000000000000000000000000000000000000088000000000000000080a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b4218080") + return fromRlp("f90482a05e0415a04370b022b7a003e86fdd29e13e8781435867230cc6e5ff45e1924cbea01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948fdaaa7e6631e438625ca25c857a3727ea28e565a0bae6330554017c1046039ecbd12d5e62956bf2af0bc371415b4778d5b33a085fa056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000028201f48402625a00808467d7b8bbb90223d883010507846765746888676f312e32332e37856c696e75780000001c8a30c0048fdaaa7e6631e438625ca25c857a3727ea28e565b00d73deea8ca44ff831d529526b46ac87dc187399497f5b2b671371fe86232004649c5ee362ef07c388f2c7f2cb7198a7876ea32e7a748c697d01345145485561305b24b1e91d15cdacddb71c64a5227970bd4f99376c40387efb60274a093429de86c81a85f448706d5e4214a406f47db1fa08d9a13701eafb76870cb220843b8c6476824bfa158668fccdfba6b5d5bc1a39e431d716ea715244473169f178d9af70c33b89a7481f54098cf885c8db140fdcd55ad5e4e9e04db2de85453e0936b441c339a26d10cfa71b50a258fb77ce7f0d3ac60e0d97fdade3efe76d8e6950ce30b40aa9914f7b2d42c247cbd36821d8741739dea2451720926901f8ae0fb860a7c69dd2e73ffb364f69c37bded01a0b6a4ed65dbc6d8f86bf4e96f1372273d6b91e7e4e74976067acf10aab91ce53c508376fbd5d29c3a9387b6ffca3d190a8e375d1c3bf55cb104738c99bc8882afb20b8dc6b3c02a7d9c40fa0ed02937ad6f8488201f2a0074b91607b4a91e13eef4df4ad575ec25da52100a0d56a481803dd41143c90838201f3a05e0415a04370b022b7a003e86fdd29e13e8781435867230cc6e5ff45e1924cbe8031443f1f703eae6925ce1036aa58458d8d7673ef4d0f40a7ea18a0ef91f1a07c62ffe6be3e7db067ec696db0d9e6be5c50ffe4482f05b79f9c55a7b4ca5d58ca01a0000000000000000000000000000000000000000000000000000000000000000088000000000000000080a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b4218080a00000000000000000000000000000000000000000000000000000000000000000a0e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855") } func epochHeader() *types.Header { - return fromRlp("f90442a04ec3c90370deeeab62de72108470bccac75d1abe118a778f01afa7a99c976a5da01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948fdaaa7e6631e438625ca25c857a3727ea28e565a08d30abd786d85a8a10ba441afafdf853b7fd2769351f6600402b88a1ac2d4d7aa0015ebe4a5d6cd56f0bf97db1d21746f59ab5cbecf216e34753920d815403ada2a03cd1ebc99cd975182c58de47be968c97658cff4c465e20654185f408a851403cb9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000028201908402625a008229a884669a6ce9b90223d98301040b846765746889676f312e32312e3132856c696e7578000020155b72048fdaaa7e6631e438625ca25c857a3727ea28e565b94a73be71b4a5703b4d0b36e4f65d52615b668b385efc047f7f385ace378981fa3750a0bc16ca6f8217be599bcfa274a7876ea32e7a748c697d01345145485561305b248cd0ede772633b8baea9958f9b602db36d78934d948244a13c2d66e998f987783276e9aee6facbff50b0d63574406b51b2e42bc54d19116d2348ac83461e2e0915d508ad921ebe99c27c8fdbd30aecdbe86f95aee2e06995f83ebeb327924669629f193ffd3257315c79ed5a4867ec53b502b5e6e04db2de85453e0936b441c339a26d10cfa71b50a50dd5edefbafd33740101d074b6d58b56a787a7644ddfff77d0c00f9e62cc58c931e671afc564f3f6e255cc6fc8a56701f8ae0fb8608b6dc552b410a6fa44fa31643850bcb314f1d4edb32c0c79ee3efef5397691f3685d80057d77510a00e77a39e8b2497419053c3b81a8901e85590a20a0a2dad529c82f6c175ec3ebca8a9112415aa94718af673c16c0e90e327e27709666e499f84882018ea0709f88597f05218c198818991cf5598c9280db30d5bfe899da9b7a8c963bff6c82018fa04ec3c90370deeeab62de72108470bccac75d1abe118a778f01afa7a99c976a5d8012518315e9c22a4a648f4d26efcf57f877a26498de6d53fe7a267e8d5ef01482009817fc9de90ca8008ef1f420aa606ddc0c56a975bace3906601fd5cde657d600a0000000000000000000000000000000000000000000000000000000000000000088000000000000000080a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b4218080") + return fromRlp("f90484a0322d19e268300c0c825ffdc22a4376232406b925a7c4be8727f9a4425818ec8aa01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948fdaaa7e6631e438625ca25c857a3727ea28e565a04c35879f76cd366249e5810ce3ff0a4be2f4e1a995e004fa207bcbece6b43bf2a0e0781acd204a300b1a607656df80d8a3ab2684fb6fa9e83d4087aa9e9157330ca03cd1ebc99cd975182c58de47be968c97658cff4c465e20654185f408a851403cb9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000028203e88402625a008229a88467d7bba9b90223d883010507846765746888676f312e32332e37856c696e75780000001c8a30c0048fdaaa7e6631e438625ca25c857a3727ea28e565b00d73deea8ca44ff831d529526b46ac87dc187399497f5b2b671371fe86232004649c5ee362ef07c388f2c7f2cb7198a7876ea32e7a748c697d01345145485561305b24b1e91d15cdacddb71c64a5227970bd4f99376c40387efb60274a093429de86c81a85f448706d5e4214a406f47db1fa08d9a13701eafb76870cb220843b8c6476824bfa158668fccdfba6b5d5bc1a39e431d716ea715244473169f178d9af70c33b89a7481f54098cf885c8db140fdcd55ad5e4e9e04db2de85453e0936b441c339a26d10cfa71b50a258fb77ce7f0d3ac60e0d97fdade3efe76d8e6950ce30b40aa9914f7b2d42c247cbd36821d8741739dea2451720926906f8ae0fb86099f5bd42d7a4e11f283b9daa22fe1f7ae89e5260b61722ec3f57dc2b18a669e0040e42a6f81d114732c00609d4648b0d0fec3a07fb300cf49a7cf6116abb217b13a63ee6330663349e8a316c42dc04f16131445a331365d2b32bcb4d5b546c25f8488203e6a0302d35ff53c930401473e5650e8169f18f1156d0127cd1bd1a3e65fe365c5efc8203e7a0322d19e268300c0c825ffdc22a4376232406b925a7c4be8727f9a4425818ec8a80a240096b876248068d454519a30d241182b95497f8a66d6d179495e9fd6d9427096f4c35eb87299f195d8fd4731d162a2c8ab445dd0ea56989288b2825c640c100a0000000000000000000000000000000000000000000000000000000000000000088000000000000000080a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b4218080a00000000000000000000000000000000000000000000000000000000000000000a0e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855") } func epochHeaderPlus1() *types.Header { - return fromRlp("f9032ea0e256fac4dd62cc71eaefd8d6c24ae5209c0e48f5c0b62bcced06dfa838c2ad31a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794b2e42bc54d19116d2348ac83461e2e0915d508ada08d30abd786d85a8a10ba441afafdf853b7fd2769351f6600402b88a1ac2d4d7aa056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000028201918402625a008084669a6cecb90111d98301040b846765746889676f312e32312e3132856c696e7578000020155b72f8ae0fb8609338bf42b6ef715e9c887e1b285e706355c2a993cd227497b447f8aad4b7fa44d18cd895862e1a2b961b78656d620f9c015e777cf9bcb6c50e1db2783818bd91f647f6879f8bd199f266f1166f9241f00f955fb5210e7e89e7678680900d1cc1f84882018fa04ec3c90370deeeab62de72108470bccac75d1abe118a778f01afa7a99c976a5d820190a0e256fac4dd62cc71eaefd8d6c24ae5209c0e48f5c0b62bcced06dfa838c2ad3180d6c559fceda3795918a2fdd34cb4f77608c8095b67091aadcef5d5c4efe09fc0477a1977c0037f19244240648637c3c5ec9fe22f1db4899a022575bec96cfccf01a0000000000000000000000000000000000000000000000000000000000000000088000000000000000080a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b4218080") + return fromRlp("f90370a03a302bedfa30dd88b82a95136a99d93ea8863a741c2201ad77a63d0f9c0c329ca01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794a7876ea32e7a748c697d01345145485561305b24a04ff32807d3701bcff50e1213fdce58ce988fb64c9e1cc269874a3d970ef7d1e8a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000028203e98402625a00808467d7bbaab90111d883010507846765746888676f312e32332e37856c696e75780000001c8a30c0f8ae0fb860a51854c31fb60a02ba70c07eeb467be677b9548c828607f99dfd0edc80a9b25be05670b86485dd71d8fb8e19d7458a9103d942ea6b84070ed47adcd3a3f284385fc538a5f692289c3abc25372e461a54ef23100718aedf80224a1e4fe26671d3f8488203e7a0322d19e268300c0c825ffdc22a4376232406b925a7c4be8727f9a4425818ec8a8203e8a03a302bedfa30dd88b82a95136a99d93ea8863a741c2201ad77a63d0f9c0c329c80313317225cc094c83c097e6a830295a3e3a6df48baadc709927d7d2bc643d9ef4d474ff4442565ef2c0bf90644095ee4d3a9934650d1b989f9d82ba9d664e57100a000000000000000000000000000000000000000000000000000000000000001f488000000000000000080a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b4218080a00000000000000000000000000000000000000000000000000000000000000000a0e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855") } func epochHeaderPlus2() *types.Header { - return fromRlp("f9032ea0669cf9fc3b3d480d7a8de1cc051e1d95fa24be8870aa93bb5bfc03f1d592db46a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794d9a13701eafb76870cb220843b8c6476824bfa15a08d30abd786d85a8a10ba441afafdf853b7fd2769351f6600402b88a1ac2d4d7aa056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000028201928402625a008084669a6cefb90111d98301040b846765746889676f312e32312e3132856c696e7578000020155b72f8ae0fb8608d465cf004274c6caaddd041116c93f12cba458536d23efc6148134af357a685c7b84b1d3de59eb61b2756e7b99a99de00a6158245e16d23dd10602ef719836ce41862c567745727a145df4bde737415e8ffbec5056d4653b02fe1ddc8f21069f848820190a0e256fac4dd62cc71eaefd8d6c24ae5209c0e48f5c0b62bcced06dfa838c2ad31820191a0669cf9fc3b3d480d7a8de1cc051e1d95fa24be8870aa93bb5bfc03f1d592db468083bec325b33996ad2fc35e146d7e8fd215177b1423378d3b07cb73293d5384733488a981b64ae03cbcf44af281cfbd57431addbd8432042c49fb4c78d5573f0d01a0000000000000000000000000000000000000000000000000000000000000000088000000000000000080a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b4218080") + return fromRlp("f90370a04e490385e3e7a962e9f76d0a07d84d23920c6c35f18e1f789370256e6c987acda01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794d9a13701eafb76870cb220843b8c6476824bfa15a08c694a1f89eafbe7d2a2e08e4e64f855159fe234cb26637edf6a166429d4f338a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000028203ea8402625a00808467d7bbacb90111d883010507846765746888676f312e32332e37856c696e75780000001c8a30c0f8ae0fb86094e9755690770485712c5b0f060b43d2bd542c3712146d8542053d4f42d05bf253ed5ee05efb85862f2faf4b6c25279e1735110b78af88000b4c90462ff318fc195be0b1a7a0d4e41943ec288aafab6eb3c5ebc31dd2a0ce428cceebf20553aef8488203e8a03a302bedfa30dd88b82a95136a99d93ea8863a741c2201ad77a63d0f9c0c329c8203e9a04e490385e3e7a962e9f76d0a07d84d23920c6c35f18e1f789370256e6c987acd8020c2f74f57683c3ca4405ad21e3fdf74c30624571bbcf7b88cf27d4b12631ac9069c6fa8ff35fac1662e9bc89dc040cec541fd36aee8c8058c299bafc0ed5d1700a0000000000000000000000000000000000000000000000000000000000000000088000000000000000080a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b4218080a00000000000000000000000000000000000000000000000000000000000000000a0e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855") } func epochHeaderPlus3() *types.Header { - return fromRlp("f9032ea0705444384ac2acf605c4ca8353e5070f37cc0976597dfdfc74413e278725eee7a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794e04db2de85453e0936b441c339a26d10cfa71b50a08d30abd786d85a8a10ba441afafdf853b7fd2769351f6600402b88a1ac2d4d7aa056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000028201938402625a008084669a6cf2b90111d98301040b846765746889676f312e32312e3132856c696e7578000020155b72f8ae0fb860a6e88879bc7f8ff4ee90ba0776b414b97ffcb0a2bc4f9484075ea121e00b7ce27e21c0fbf76f34746b232e76a37cfc220011efbd7863237e75eb2830748736e9092847a283401bf6793e94d00619764884d012609cf5bace403e93b66f60c3bcf848820191a0669cf9fc3b3d480d7a8de1cc051e1d95fa24be8870aa93bb5bfc03f1d592db46820192a0705444384ac2acf605c4ca8353e5070f37cc0976597dfdfc74413e278725eee780f5171f7fc98ba3118543b55677128c397b07085a29dcd71c989c7f0eb602308342cf64470f85ebe31ebdda4244e7992b82ff2026ac461d0f2997332ccb99255201a0000000000000000000000000000000000000000000000000000000000000000088000000000000000080a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b4218080") + return fromRlp("f90370a04efd97fb852943cd7e995432bfb2d3ec64847f7e84b37d5a3022d7b3c04abd24a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794e04db2de85453e0936b441c339a26d10cfa71b50a0167484b0a23d96c53238b8e02465ce28353b86bde23a4c76079c206ef68c9646a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000028203eb8402625a00808467d7bbadb90111d883010507846765746888676f312e32332e37856c696e75780000001c8a30c0f8ae0fb860acaa8373b727de717178de93621351e285bc9803b59af041bcf6125421adb461838a18c251c2fe3e747b4081010e429411a750ddc02871238102ac2df09bcb6085b48d9061f23dda19b5084c1b6b8cbdf816f29643413a0b616ba24a3b00145bf8488203e9a04e490385e3e7a962e9f76d0a07d84d23920c6c35f18e1f789370256e6c987acd8203eaa04efd97fb852943cd7e995432bfb2d3ec64847f7e84b37d5a3022d7b3c04abd24805444abf4fc554f34fd1f7e8e768ffa50740d4cbe373175fa115bc3b674d4d2322496a207e5d5bf5224071a161d9194db4b9c4e628e3214c3f4c35bf194998b0c00a000000000000000000000000000000000000000000000000000000000000001f488000000000000000080a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b4218080a00000000000000000000000000000000000000000000000000000000000000000a0e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855") } func headerByHeight(height int64) *types.Header { switch height { - case 200: + case 500: return previousEpochHeader() - case 400: + case 1000: return epochHeader() - case 401: + case 1001: return epochHeaderPlus1() - case 402: + case 1002: return epochHeaderPlus2() - case 403: + case 1003: return epochHeaderPlus3() } return nil diff --git a/module/parlia.pb.go b/module/parlia.pb.go index 9032ed80..6915774d 100644 --- a/module/parlia.pb.go +++ b/module/parlia.pb.go @@ -28,6 +28,94 @@ var _ = time.Kitchen // proto package needs to be updated. const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package +type ForkSpec struct { + // Types that are valid to be assigned to HeightOrTimestamp: + // *ForkSpec_Height + // *ForkSpec_Timestamp + HeightOrTimestamp isForkSpec_HeightOrTimestamp `protobuf_oneof:"height_or_timestamp"` + AdditionalHeaderItemCount uint64 `protobuf:"varint,3,opt,name=additional_header_item_count,json=additionalHeaderItemCount,proto3" json:"additional_header_item_count,omitempty"` + EpochLength uint64 `protobuf:"varint,4,opt,name=epoch_length,json=epochLength,proto3" json:"epoch_length,omitempty"` + MaxTurnLength uint64 `protobuf:"varint,5,opt,name=max_turn_length,json=maxTurnLength,proto3" json:"max_turn_length,omitempty"` +} + +func (m *ForkSpec) Reset() { *m = ForkSpec{} } +func (m *ForkSpec) String() string { return proto.CompactTextString(m) } +func (*ForkSpec) ProtoMessage() {} +func (*ForkSpec) Descriptor() ([]byte, []int) { + return fileDescriptor_dc631224085c6c85, []int{0} +} +func (m *ForkSpec) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ForkSpec) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ForkSpec.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ForkSpec) XXX_Merge(src proto.Message) { + xxx_messageInfo_ForkSpec.Merge(m, src) +} +func (m *ForkSpec) XXX_Size() int { + return m.Size() +} +func (m *ForkSpec) XXX_DiscardUnknown() { + xxx_messageInfo_ForkSpec.DiscardUnknown(m) +} + +var xxx_messageInfo_ForkSpec proto.InternalMessageInfo + +type isForkSpec_HeightOrTimestamp interface { + isForkSpec_HeightOrTimestamp() + MarshalTo([]byte) (int, error) + Size() int +} + +type ForkSpec_Height struct { + Height uint64 `protobuf:"varint,1,opt,name=height,proto3,oneof" json:"height,omitempty"` +} +type ForkSpec_Timestamp struct { + Timestamp uint64 `protobuf:"varint,2,opt,name=timestamp,proto3,oneof" json:"timestamp,omitempty"` +} + +func (*ForkSpec_Height) isForkSpec_HeightOrTimestamp() {} +func (*ForkSpec_Timestamp) isForkSpec_HeightOrTimestamp() {} + +func (m *ForkSpec) GetHeightOrTimestamp() isForkSpec_HeightOrTimestamp { + if m != nil { + return m.HeightOrTimestamp + } + return nil +} + +func (m *ForkSpec) GetHeight() uint64 { + if x, ok := m.GetHeightOrTimestamp().(*ForkSpec_Height); ok { + return x.Height + } + return 0 +} + +func (m *ForkSpec) GetTimestamp() uint64 { + if x, ok := m.GetHeightOrTimestamp().(*ForkSpec_Timestamp); ok { + return x.Timestamp + } + return 0 +} + +// XXX_OneofWrappers is for the internal use of the proto package. +func (*ForkSpec) XXX_OneofWrappers() []interface{} { + return []interface{}{ + (*ForkSpec_Height)(nil), + (*ForkSpec_Timestamp)(nil), + } +} + type ClientState struct { ChainId uint64 `protobuf:"varint,1,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"` IbcStoreAddress []byte `protobuf:"bytes,2,opt,name=ibc_store_address,json=ibcStoreAddress,proto3" json:"ibc_store_address,omitempty"` @@ -36,13 +124,14 @@ type ClientState struct { TrustingPeriod time.Duration `protobuf:"bytes,5,opt,name=trusting_period,json=trustingPeriod,proto3,stdduration" json:"trusting_period"` MaxClockDrift time.Duration `protobuf:"bytes,6,opt,name=max_clock_drift,json=maxClockDrift,proto3,stdduration" json:"max_clock_drift"` Frozen bool `protobuf:"varint,7,opt,name=frozen,proto3" json:"frozen,omitempty"` + ForkSpecs []*ForkSpec `protobuf:"bytes,8,rep,name=fork_specs,json=forkSpecs,proto3" json:"fork_specs,omitempty"` } func (m *ClientState) Reset() { *m = ClientState{} } func (m *ClientState) String() string { return proto.CompactTextString(m) } func (*ClientState) ProtoMessage() {} func (*ClientState) Descriptor() ([]byte, []int) { - return fileDescriptor_dc631224085c6c85, []int{0} + return fileDescriptor_dc631224085c6c85, []int{1} } func (m *ClientState) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -79,7 +168,7 @@ func (m *ETHHeader) Reset() { *m = ETHHeader{} } func (m *ETHHeader) String() string { return proto.CompactTextString(m) } func (*ETHHeader) ProtoMessage() {} func (*ETHHeader) Descriptor() ([]byte, []int) { - return fileDescriptor_dc631224085c6c85, []int{1} + return fileDescriptor_dc631224085c6c85, []int{2} } func (m *ETHHeader) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -121,7 +210,7 @@ func (m *Header) Reset() { *m = Header{} } func (m *Header) String() string { return proto.CompactTextString(m) } func (*Header) ProtoMessage() {} func (*Header) Descriptor() ([]byte, []int) { - return fileDescriptor_dc631224085c6c85, []int{2} + return fileDescriptor_dc631224085c6c85, []int{3} } func (m *Header) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -161,7 +250,7 @@ func (m *ConsensusState) Reset() { *m = ConsensusState{} } func (m *ConsensusState) String() string { return proto.CompactTextString(m) } func (*ConsensusState) ProtoMessage() {} func (*ConsensusState) Descriptor() ([]byte, []int) { - return fileDescriptor_dc631224085c6c85, []int{3} + return fileDescriptor_dc631224085c6c85, []int{4} } func (m *ConsensusState) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -200,7 +289,7 @@ func (m *Misbehaviour) Reset() { *m = Misbehaviour{} } func (m *Misbehaviour) String() string { return proto.CompactTextString(m) } func (*Misbehaviour) ProtoMessage() {} func (*Misbehaviour) Descriptor() ([]byte, []int) { - return fileDescriptor_dc631224085c6c85, []int{4} + return fileDescriptor_dc631224085c6c85, []int{5} } func (m *Misbehaviour) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -238,7 +327,7 @@ func (m *ProveState) Reset() { *m = ProveState{} } func (m *ProveState) String() string { return proto.CompactTextString(m) } func (*ProveState) ProtoMessage() {} func (*ProveState) Descriptor() ([]byte, []int) { - return fileDescriptor_dc631224085c6c85, []int{5} + return fileDescriptor_dc631224085c6c85, []int{6} } func (m *ProveState) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -268,6 +357,7 @@ func (m *ProveState) XXX_DiscardUnknown() { var xxx_messageInfo_ProveState proto.InternalMessageInfo func init() { + proto.RegisterType((*ForkSpec)(nil), "ibc.lightclients.parlia.v1.ForkSpec") proto.RegisterType((*ClientState)(nil), "ibc.lightclients.parlia.v1.ClientState") proto.RegisterType((*ETHHeader)(nil), "ibc.lightclients.parlia.v1.ETHHeader") proto.RegisterType((*Header)(nil), "ibc.lightclients.parlia.v1.Header") @@ -281,57 +371,136 @@ func init() { } var fileDescriptor_dc631224085c6c85 = []byte{ - // 761 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x94, 0xcd, 0x6e, 0xeb, 0x44, - 0x14, 0xc7, 0xe3, 0x24, 0xa4, 0xc9, 0x34, 0xb9, 0xe5, 0xce, 0xbd, 0x5c, 0x7c, 0x03, 0xb8, 0x51, - 0x2a, 0x44, 0x40, 0xaa, 0x4d, 0x82, 0x84, 0xd8, 0xa0, 0xaa, 0x4d, 0x91, 0x52, 0xd1, 0x4a, 0x95, - 0x5b, 0xb1, 0x40, 0x48, 0xd6, 0x78, 0x3c, 0xb1, 0x47, 0xd8, 0x9e, 0x68, 0x66, 0x1c, 0x15, 0x9e, - 0x82, 0x25, 0xaf, 0xc0, 0x53, 0xb0, 0xed, 0x0a, 0x75, 0xc9, 0x8a, 0x8f, 0xf6, 0x2d, 0x58, 0xa1, - 0xf9, 0xc8, 0x07, 0x2a, 0x5f, 0x77, 0x37, 0x73, 0xce, 0xff, 0x77, 0xc6, 0xe7, 0x3f, 0xc7, 0x03, - 0xde, 0xa3, 0x31, 0x0e, 0x72, 0x9a, 0x66, 0x12, 0xe7, 0x94, 0x94, 0x52, 0x04, 0x0b, 0xc4, 0x73, - 0x8a, 0x82, 0xe5, 0xd8, 0xae, 0xfc, 0x05, 0x67, 0x92, 0xc1, 0x3e, 0x8d, 0xb1, 0xbf, 0x2d, 0xf4, - 0x6d, 0x7a, 0x39, 0xee, 0x3f, 0x4f, 0x59, 0xca, 0xb4, 0x2c, 0x50, 0x2b, 0x43, 0xf4, 0xf7, 0x55, - 0x69, 0xcc, 0x38, 0x09, 0x0c, 0xa1, 0x4a, 0x9a, 0x95, 0x15, 0x78, 0x29, 0x63, 0x69, 0x4e, 0x02, - 0xbd, 0x8b, 0xab, 0x79, 0x90, 0x54, 0x1c, 0x49, 0xca, 0x4a, 0x93, 0x1f, 0xfe, 0x51, 0x07, 0xbb, - 0x53, 0x0d, 0x5c, 0x49, 0x24, 0x09, 0x7c, 0x09, 0xda, 0x38, 0x43, 0xb4, 0x8c, 0x68, 0xe2, 0x3a, - 0x03, 0x67, 0xd4, 0x0c, 0x77, 0xf4, 0xfe, 0x2c, 0x81, 0x1f, 0x80, 0xa7, 0x34, 0xc6, 0x91, 0x90, - 0x8c, 0x93, 0x08, 0x25, 0x09, 0x27, 0x42, 0xb8, 0xf5, 0x81, 0x33, 0xea, 0x86, 0x7b, 0x34, 0xc6, - 0x57, 0x2a, 0x7e, 0x6c, 0xc2, 0xf0, 0x43, 0xf0, 0x5c, 0x69, 0x31, 0x2b, 0x0a, 0x2a, 0x0b, 0xd5, - 0x4a, 0x24, 0x72, 0x26, 0xdd, 0x86, 0x96, 0x43, 0x1a, 0xe3, 0xe9, 0x26, 0x75, 0x95, 0x33, 0x09, - 0x8f, 0x40, 0x2f, 0x47, 0x92, 0x08, 0x19, 0x65, 0x44, 0x39, 0xe0, 0x36, 0x07, 0xce, 0x68, 0x77, - 0xd2, 0xf7, 0x95, 0x27, 0xaa, 0x43, 0xdf, 0xf6, 0xb5, 0x1c, 0xfb, 0x33, 0xad, 0x08, 0xbb, 0x06, - 0x30, 0x3b, 0x78, 0x0e, 0xf6, 0x24, 0xaf, 0x84, 0xa4, 0x65, 0x1a, 0x2d, 0x08, 0xa7, 0x2c, 0x71, - 0x5f, 0xd3, 0x25, 0x5e, 0xfa, 0xc6, 0x03, 0x7f, 0xe5, 0x81, 0x7f, 0x6a, 0x3d, 0x38, 0x69, 0xdf, - 0xfe, 0xb2, 0x5f, 0xfb, 0xfe, 0xd7, 0x7d, 0x27, 0x7c, 0xb2, 0x62, 0x2f, 0x35, 0x0a, 0x3f, 0x07, - 0x7b, 0x05, 0xba, 0x89, 0x70, 0xce, 0xf0, 0xd7, 0x51, 0xc2, 0xe9, 0x5c, 0xba, 0xad, 0xff, 0x5f, - 0xad, 0x57, 0xa0, 0x9b, 0xa9, 0x42, 0x4f, 0x15, 0x09, 0x5f, 0x80, 0xd6, 0x9c, 0xb3, 0x6f, 0x49, - 0xe9, 0xee, 0x0c, 0x9c, 0x51, 0x3b, 0xb4, 0xbb, 0xe1, 0x01, 0xe8, 0x7c, 0x76, 0x3d, 0x9b, 0x11, - 0x94, 0x10, 0xae, 0x44, 0x99, 0x5e, 0x69, 0xdf, 0xbb, 0xa1, 0xdd, 0x0d, 0x7f, 0xaa, 0x83, 0x96, - 0x95, 0x1c, 0x81, 0x1d, 0x13, 0x14, 0xae, 0x33, 0x68, 0x8c, 0x76, 0x27, 0xef, 0xfa, 0xff, 0x3c, - 0x31, 0xfe, 0xba, 0x74, 0xb8, 0xa2, 0xe0, 0x31, 0x30, 0x7d, 0x92, 0x64, 0xe5, 0x72, 0xfd, 0x3f, - 0x5d, 0xee, 0x59, 0xc2, 0xda, 0x7c, 0x08, 0x20, 0xae, 0x38, 0x27, 0xa5, 0x8c, 0x96, 0x28, 0xa7, - 0x09, 0x92, 0x8c, 0x0b, 0xb7, 0x31, 0x68, 0x8c, 0xba, 0xe1, 0x53, 0x9b, 0xf9, 0x62, 0x9d, 0x80, - 0x01, 0x78, 0xb6, 0xe0, 0x64, 0x49, 0x59, 0x25, 0xb6, 0xf5, 0x4d, 0xad, 0x87, 0xab, 0xd4, 0x16, - 0xe0, 0x83, 0x67, 0xab, 0xfa, 0xb2, 0xe2, 0x65, 0x94, 0x93, 0x32, 0x95, 0x99, 0xbe, 0xca, 0xde, - 0xfa, 0x80, 0xeb, 0x8a, 0x97, 0xe7, 0x3a, 0xa1, 0x26, 0x6d, 0x7d, 0xc0, 0x36, 0xd0, 0xd2, 0xc0, - 0xfa, 0x84, 0x0d, 0x31, 0xfc, 0xd1, 0x01, 0x4f, 0xa6, 0xac, 0x14, 0xa4, 0x14, 0x95, 0x30, 0x53, - 0xff, 0x0e, 0x00, 0x42, 0x2d, 0x22, 0xce, 0x98, 0xb4, 0xfe, 0x77, 0x74, 0x24, 0x64, 0x4c, 0xc2, - 0xb7, 0x41, 0x47, 0xd2, 0x82, 0x08, 0x89, 0x8a, 0x85, 0x76, 0xac, 0x19, 0x6e, 0x02, 0xf0, 0x63, - 0xf0, 0xe6, 0x63, 0x47, 0xa2, 0x0c, 0x89, 0xcc, 0x8e, 0xfb, 0x1b, 0x8f, 0x6c, 0x99, 0x21, 0x91, - 0xc1, 0x4f, 0x80, 0xfb, 0x37, 0xd6, 0x18, 0xb0, 0xa9, 0xc1, 0x17, 0x8f, 0xfd, 0x51, 0xe4, 0xf0, - 0x07, 0x07, 0x74, 0x2f, 0xa8, 0x88, 0x49, 0x86, 0x54, 0x9a, 0xc3, 0xb7, 0x40, 0xc7, 0xdc, 0xdb, - 0xea, 0xb7, 0xed, 0x84, 0x6d, 0x13, 0x38, 0x4b, 0xe0, 0xa7, 0xa0, 0x6d, 0xee, 0x3f, 0x1a, 0xdb, - 0xeb, 0x1e, 0xfe, 0xdb, 0xd8, 0xfc, 0x75, 0x66, 0xc6, 0x5b, 0xf8, 0x44, 0xf7, 0xf3, 0x4a, 0xf8, - 0x64, 0xf8, 0x15, 0x00, 0x97, 0x9c, 0x2d, 0x89, 0x31, 0xfa, 0x00, 0xf4, 0x10, 0xc6, 0xac, 0x2a, - 0x65, 0xb4, 0xe0, 0x8c, 0xcd, 0xad, 0xd7, 0x5d, 0x1b, 0xbc, 0x54, 0x31, 0xf8, 0x3e, 0x78, 0x7d, - 0xf3, 0x70, 0x58, 0x9d, 0x7d, 0x67, 0x36, 0x71, 0x2d, 0x3d, 0xb9, 0xb8, 0xfd, 0xdd, 0xab, 0xdd, - 0xde, 0x7b, 0xce, 0xdd, 0xbd, 0xe7, 0xfc, 0x76, 0xef, 0x39, 0xdf, 0x3d, 0x78, 0xb5, 0xbb, 0x07, - 0xaf, 0xf6, 0xf3, 0x83, 0x57, 0xfb, 0x32, 0x48, 0xa9, 0xcc, 0xaa, 0xd8, 0xc7, 0xac, 0x08, 0x12, - 0x24, 0x91, 0x7e, 0xc9, 0x72, 0x14, 0x07, 0x34, 0xc6, 0x87, 0xe6, 0x93, 0x0f, 0x39, 0xc9, 0xd1, - 0x37, 0x41, 0xc1, 0x92, 0x2a, 0x27, 0x71, 0x4b, 0xff, 0xd4, 0x1f, 0xfd, 0x19, 0x00, 0x00, 0xff, - 0xff, 0x0f, 0xe3, 0xdf, 0x4c, 0xb2, 0x05, 0x00, 0x00, + // 882 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x54, 0x4d, 0x6f, 0x23, 0x35, + 0x18, 0xce, 0x34, 0x25, 0x4d, 0x9c, 0x64, 0xcb, 0xba, 0xbb, 0xcb, 0xb4, 0x2c, 0x69, 0xc9, 0xf2, + 0x51, 0x90, 0x3a, 0x43, 0x82, 0x84, 0xb8, 0xa0, 0x6a, 0x9b, 0x05, 0xa5, 0x62, 0x57, 0xaa, 0xa6, + 0x2b, 0x0e, 0x08, 0xc9, 0xf2, 0x78, 0x9c, 0x8c, 0xd5, 0x99, 0xf1, 0xc8, 0xf6, 0x44, 0x0b, 0xbf, + 0x82, 0x23, 0x7f, 0x81, 0x5f, 0xb1, 0xd7, 0x9e, 0xd0, 0x1e, 0x39, 0xf1, 0xd1, 0x1e, 0xf8, 0x1b, + 0xc8, 0x1f, 0x93, 0x04, 0x0a, 0x0b, 0x7b, 0xb3, 0xdf, 0xf7, 0x79, 0xfc, 0xda, 0xcf, 0xf3, 0xfa, + 0x05, 0xef, 0xb3, 0x98, 0x84, 0x19, 0x9b, 0xa7, 0x8a, 0x64, 0x8c, 0x16, 0x4a, 0x86, 0x25, 0x16, + 0x19, 0xc3, 0xe1, 0x62, 0xe4, 0x56, 0x41, 0x29, 0xb8, 0xe2, 0x70, 0x8f, 0xc5, 0x24, 0x58, 0x07, + 0x06, 0x2e, 0xbd, 0x18, 0xed, 0xdd, 0x99, 0xf3, 0x39, 0x37, 0xb0, 0x50, 0xaf, 0x2c, 0x63, 0x6f, + 0x5f, 0x1f, 0x4d, 0xb8, 0xa0, 0xa1, 0x65, 0xe8, 0x23, 0xed, 0xca, 0x01, 0x06, 0x73, 0xce, 0xe7, + 0x19, 0x0d, 0xcd, 0x2e, 0xae, 0x66, 0x61, 0x52, 0x09, 0xac, 0x18, 0x2f, 0x6c, 0x7e, 0xf8, 0x87, + 0x07, 0xda, 0x5f, 0x70, 0x71, 0x71, 0x5e, 0x52, 0x02, 0x7d, 0xd0, 0x4a, 0xa9, 0x2e, 0xef, 0x7b, + 0x07, 0xde, 0xe1, 0xe6, 0xb4, 0x11, 0xb9, 0x3d, 0x1c, 0x80, 0x8e, 0x62, 0x39, 0x95, 0x0a, 0xe7, + 0xa5, 0xbf, 0xe1, 0x92, 0xab, 0x10, 0x3c, 0x06, 0xf7, 0x71, 0x92, 0x30, 0x7d, 0x30, 0xce, 0x50, + 0x4a, 0x71, 0x42, 0x05, 0x62, 0x8a, 0xe6, 0x88, 0xf0, 0xaa, 0x50, 0x7e, 0x53, 0x53, 0xa2, 0xdd, + 0x15, 0x66, 0x6a, 0x20, 0xa7, 0x8a, 0xe6, 0x13, 0x0d, 0x80, 0x6f, 0x83, 0x1e, 0x2d, 0x39, 0x49, + 0x51, 0x46, 0x8b, 0xb9, 0x4a, 0xfd, 0x4d, 0x43, 0xe8, 0x9a, 0xd8, 0x63, 0x13, 0x82, 0xef, 0x81, + 0xed, 0x1c, 0x3f, 0x43, 0xaa, 0x12, 0x45, 0x8d, 0x7a, 0xcd, 0xa0, 0xfa, 0x39, 0x7e, 0xf6, 0xb4, + 0x12, 0x85, 0xc5, 0x9d, 0xdc, 0x05, 0x3b, 0xf6, 0xd6, 0x88, 0x0b, 0xb4, 0xbc, 0xe2, 0xf0, 0x79, + 0x13, 0x74, 0x27, 0x46, 0x9a, 0x73, 0x85, 0x15, 0x85, 0xbb, 0xa0, 0x4d, 0x52, 0xcc, 0x0a, 0xc4, + 0x12, 0xfb, 0xdc, 0x68, 0xcb, 0xec, 0x4f, 0x13, 0xf8, 0x21, 0xb8, 0xcd, 0x62, 0x82, 0xa4, 0xe2, + 0x82, 0x22, 0x9c, 0x24, 0x82, 0x4a, 0x69, 0x5e, 0xdd, 0x8b, 0xb6, 0x59, 0x4c, 0xce, 0x75, 0xfc, + 0xa1, 0x0d, 0xc3, 0x8f, 0xc0, 0x1d, 0x8d, 0x25, 0x3c, 0xcf, 0x99, 0xca, 0xb5, 0x69, 0x48, 0x66, + 0xdc, 0xbe, 0xb8, 0x17, 0x41, 0x16, 0x93, 0xc9, 0x2a, 0x75, 0x9e, 0x71, 0x05, 0x8f, 0x41, 0x3f, + 0xc3, 0x8a, 0x4a, 0x85, 0x9c, 0xd8, 0xfa, 0xad, 0xdd, 0xf1, 0x5e, 0xa0, 0xdd, 0xd7, 0x5e, 0x06, + 0xce, 0xc1, 0xc5, 0x28, 0x98, 0x1a, 0x44, 0xd4, 0xb3, 0x04, 0xbb, 0x83, 0x8f, 0xc1, 0xb6, 0x12, + 0x95, 0x54, 0xac, 0x98, 0xa3, 0x92, 0x0a, 0xc6, 0x13, 0x23, 0x44, 0x77, 0xbc, 0x1b, 0x58, 0xb7, + 0x83, 0xda, 0xed, 0xe0, 0x91, 0x73, 0xfb, 0xa4, 0x7d, 0xf9, 0xcb, 0x7e, 0xe3, 0x87, 0x5f, 0xf7, + 0xbd, 0xe8, 0x56, 0xcd, 0x3d, 0x33, 0x54, 0xf8, 0xa5, 0x95, 0x95, 0x64, 0x9c, 0x5c, 0xa0, 0x44, + 0xb0, 0x99, 0xf2, 0x5b, 0xff, 0xff, 0x34, 0xad, 0xfd, 0x44, 0x53, 0x1f, 0x69, 0x26, 0xbc, 0x07, + 0x5a, 0x33, 0xc1, 0xbf, 0xa3, 0x85, 0xbf, 0x75, 0xe0, 0x1d, 0xb6, 0x23, 0xb7, 0x83, 0x13, 0x00, + 0x66, 0x5c, 0x5c, 0x20, 0x59, 0x52, 0x22, 0xfd, 0xf6, 0x41, 0xf3, 0xb0, 0x3b, 0x7e, 0x27, 0xf8, + 0xf7, 0x76, 0x0f, 0xea, 0x9e, 0x8c, 0x3a, 0x33, 0xb7, 0x92, 0xc3, 0x07, 0xa0, 0xf3, 0xf9, 0xd3, + 0xa9, 0xed, 0x1c, 0x5d, 0xc9, 0xb6, 0x99, 0x31, 0xaf, 0x17, 0xb9, 0xdd, 0xf0, 0xa7, 0x0d, 0xd0, + 0x72, 0x90, 0x63, 0xb0, 0x65, 0x83, 0xd2, 0xf7, 0x4c, 0xc5, 0x77, 0x5f, 0x56, 0x71, 0x79, 0x74, + 0x54, 0xb3, 0xe0, 0x43, 0x60, 0xc5, 0xa2, 0x49, 0x6d, 0xd5, 0xc6, 0x7f, 0x5a, 0xd5, 0x77, 0x0c, + 0xe7, 0xd5, 0x11, 0x80, 0xa4, 0x12, 0x82, 0x16, 0x0a, 0x2d, 0x70, 0xc6, 0x12, 0xac, 0xb8, 0x90, + 0x7e, 0xf3, 0xa0, 0x79, 0xd8, 0x8b, 0x6e, 0xbb, 0xcc, 0x57, 0xcb, 0x04, 0x0c, 0xc1, 0x4e, 0x29, + 0xe8, 0x82, 0xf1, 0x4a, 0xae, 0xe3, 0x37, 0x0d, 0x1e, 0xd6, 0xa9, 0x35, 0x42, 0x00, 0x76, 0xea, + 0xf3, 0xff, 0xfe, 0x31, 0xfa, 0xcb, 0x02, 0xab, 0xcf, 0xa1, 0xdb, 0x75, 0x59, 0x60, 0x9d, 0xd0, + 0x32, 0x84, 0x65, 0x85, 0x15, 0x63, 0xf8, 0xdc, 0x03, 0xb7, 0x26, 0xbc, 0x90, 0xb4, 0x90, 0x95, + 0xb4, 0x5f, 0xe7, 0x2d, 0x00, 0xa4, 0x5e, 0x20, 0xc1, 0xb9, 0x72, 0xfa, 0x77, 0x4c, 0x24, 0xe2, + 0x5c, 0xc1, 0xfb, 0x37, 0x86, 0xc5, 0xfa, 0xa8, 0xf8, 0x04, 0xbc, 0x71, 0x53, 0x11, 0x94, 0x62, + 0x99, 0xba, 0x3f, 0x73, 0xf7, 0x86, 0x2c, 0x53, 0x2c, 0x53, 0xf8, 0x29, 0xf0, 0xff, 0x41, 0x1a, + 0x4b, 0xdc, 0x34, 0xc4, 0x7b, 0x37, 0xf5, 0xd1, 0xcc, 0xe1, 0x8f, 0x1e, 0xe8, 0x3d, 0x61, 0x32, + 0xa6, 0x29, 0xd6, 0x69, 0x01, 0xdf, 0x04, 0x1d, 0xeb, 0x5b, 0xfd, 0xf7, 0x3b, 0x51, 0xdb, 0x06, + 0x4e, 0x13, 0xf8, 0x19, 0x68, 0xbb, 0xf9, 0x35, 0x72, 0x76, 0x0f, 0x5f, 0xd6, 0x36, 0x7f, 0xed, + 0x99, 0xd1, 0x1a, 0x7d, 0x6c, 0xde, 0xf3, 0x4a, 0xf4, 0xf1, 0xf0, 0x1b, 0x00, 0xce, 0x04, 0x5f, + 0x50, 0x2b, 0xf4, 0x03, 0xd0, 0xc7, 0xc4, 0x4c, 0x50, 0x54, 0x0a, 0xce, 0x67, 0x4e, 0xeb, 0x9e, + 0x0b, 0x9e, 0xe9, 0x18, 0xfc, 0x00, 0xbc, 0xbe, 0x9a, 0x3e, 0x0e, 0xe7, 0x86, 0xd5, 0x2a, 0x6e, + 0xa0, 0x27, 0x4f, 0x2e, 0x7f, 0x1f, 0x34, 0x2e, 0xaf, 0x06, 0xde, 0x8b, 0xab, 0x81, 0xf7, 0xdb, + 0xd5, 0xc0, 0xfb, 0xfe, 0x7a, 0xd0, 0x78, 0x71, 0x3d, 0x68, 0xfc, 0x7c, 0x3d, 0x68, 0x7c, 0x1d, + 0xce, 0x99, 0x4a, 0xab, 0x38, 0x20, 0x3c, 0x0f, 0x13, 0xac, 0xb0, 0x19, 0x87, 0x19, 0x8e, 0x43, + 0x16, 0x93, 0x23, 0x7b, 0xe5, 0x23, 0x41, 0x33, 0xfc, 0x6d, 0x98, 0xf3, 0xa4, 0xca, 0x68, 0xdc, + 0x32, 0x93, 0xe1, 0xe3, 0x3f, 0x03, 0x00, 0x00, 0xff, 0xff, 0x11, 0x5a, 0xe7, 0x6a, 0xe1, 0x06, + 0x00, 0x00, +} + +func (m *ForkSpec) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ForkSpec) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ForkSpec) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.MaxTurnLength != 0 { + i = encodeVarintParlia(dAtA, i, uint64(m.MaxTurnLength)) + i-- + dAtA[i] = 0x28 + } + if m.EpochLength != 0 { + i = encodeVarintParlia(dAtA, i, uint64(m.EpochLength)) + i-- + dAtA[i] = 0x20 + } + if m.AdditionalHeaderItemCount != 0 { + i = encodeVarintParlia(dAtA, i, uint64(m.AdditionalHeaderItemCount)) + i-- + dAtA[i] = 0x18 + } + if m.HeightOrTimestamp != nil { + { + size := m.HeightOrTimestamp.Size() + i -= size + if _, err := m.HeightOrTimestamp.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + } + } + return len(dAtA) - i, nil +} + +func (m *ForkSpec_Height) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ForkSpec_Height) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + i = encodeVarintParlia(dAtA, i, uint64(m.Height)) + i-- + dAtA[i] = 0x8 + return len(dAtA) - i, nil +} +func (m *ForkSpec_Timestamp) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) } +func (m *ForkSpec_Timestamp) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + i = encodeVarintParlia(dAtA, i, uint64(m.Timestamp)) + i-- + dAtA[i] = 0x10 + return len(dAtA) - i, nil +} func (m *ClientState) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -352,6 +521,20 @@ func (m *ClientState) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if len(m.ForkSpecs) > 0 { + for iNdEx := len(m.ForkSpecs) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.ForkSpecs[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintParlia(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x42 + } + } if m.Frozen { i-- if m.Frozen { @@ -670,6 +853,45 @@ func encodeVarintParlia(dAtA []byte, offset int, v uint64) int { dAtA[offset] = uint8(v) return base } +func (m *ForkSpec) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.HeightOrTimestamp != nil { + n += m.HeightOrTimestamp.Size() + } + if m.AdditionalHeaderItemCount != 0 { + n += 1 + sovParlia(uint64(m.AdditionalHeaderItemCount)) + } + if m.EpochLength != 0 { + n += 1 + sovParlia(uint64(m.EpochLength)) + } + if m.MaxTurnLength != 0 { + n += 1 + sovParlia(uint64(m.MaxTurnLength)) + } + return n +} + +func (m *ForkSpec_Height) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + n += 1 + sovParlia(uint64(m.Height)) + return n +} +func (m *ForkSpec_Timestamp) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + n += 1 + sovParlia(uint64(m.Timestamp)) + return n +} func (m *ClientState) Size() (n int) { if m == nil { return 0 @@ -698,6 +920,12 @@ func (m *ClientState) Size() (n int) { if m.Frozen { n += 2 } + if len(m.ForkSpecs) > 0 { + for _, e := range m.ForkSpecs { + l = e.Size() + n += 1 + l + sovParlia(uint64(l)) + } + } return n } @@ -819,6 +1047,153 @@ func sovParlia(x uint64) (n int) { func sozParlia(x uint64) (n int) { return sovParlia(uint64((x << 1) ^ uint64((int64(x) >> 63)))) } +func (m *ForkSpec) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowParlia + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ForkSpec: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ForkSpec: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Height", wireType) + } + var v uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowParlia + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.HeightOrTimestamp = &ForkSpec_Height{v} + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Timestamp", wireType) + } + var v uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowParlia + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.HeightOrTimestamp = &ForkSpec_Timestamp{v} + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field AdditionalHeaderItemCount", wireType) + } + m.AdditionalHeaderItemCount = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowParlia + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.AdditionalHeaderItemCount |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field EpochLength", wireType) + } + m.EpochLength = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowParlia + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.EpochLength |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field MaxTurnLength", wireType) + } + m.MaxTurnLength = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowParlia + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.MaxTurnLength |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipParlia(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthParlia + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *ClientState) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 @@ -1057,6 +1432,40 @@ func (m *ClientState) Unmarshal(dAtA []byte) error { } } m.Frozen = bool(v != 0) + case 8: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ForkSpecs", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowParlia + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthParlia + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthParlia + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ForkSpecs = append(m.ForkSpecs, &ForkSpec{}) + if err := m.ForkSpecs[len(m.ForkSpecs)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipParlia(dAtA[iNdEx:]) diff --git a/module/proof.go b/module/proof.go index 376eb8a2..9e33e933 100644 --- a/module/proof.go +++ b/module/proof.go @@ -4,10 +4,11 @@ import ( "bytes" "context" "fmt" - "math/big" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" "github.com/hyperledger-labs/yui-relayer/core" + "github.com/hyperledger-labs/yui-relayer/log" + "math/big" "github.com/cosmos/gogoproto/proto" "github.com/cosmos/ibc-go/v8/modules/core/exported" @@ -174,22 +175,35 @@ func verifyAccount(target *types.Header, accountProof []byte, path common.Addres return &account, nil } -func withValidators(ctx context.Context, headerFn getHeaderFn, height uint64, ethHeaders []*ETHHeader) (core.Header, error) { - +func withValidators(ctx context.Context, headerFn getHeaderFn, height uint64, ethHeaders []*ETHHeader, forkSpecs []*ForkSpec) (core.Header, error) { header := &Header{ Headers: ethHeaders, } - // Get validator set for verify headers - previousEpoch := getPreviousEpoch(height) - var previousTurnLength uint8 - var err error - header.PreviousValidators, previousTurnLength, err = queryValidatorSetAndTurnLength(ctx, headerFn, previousEpoch) - header.PreviousTurnLength = uint32(previousTurnLength) + blockHeader, err := headerFn(ctx, height) if err != nil { - return nil, fmt.Errorf("ValidatorSet was not found in previous epoch : number = %d : %+v", previousEpoch, err) + return nil, fmt.Errorf("failed to get block header : number = %d : %+v", height, err) + } + currentForkSpec, prevForkSpec, err := FindTargetForkSpec(forkSpecs, height, MilliTimestamp(blockHeader)) + if err != nil { + return nil, err + } + log.GetLogger().Debug("target fork spec", "currentForkSpec", currentForkSpec, "prevForkSpec", prevForkSpec) + + boundaryHeight, err := GetBoundaryHeight(headerFn, height, *currentForkSpec) + if err != nil { + return nil, err } - currentEpoch := getCurrentEpoch(height) + log.GetLogger().Debug("get boundary height by ", "height", height, "boundaryHeight", boundaryHeight) + + boundaryEpochs, err := boundaryHeight.GetBoundaryEpochs(*prevForkSpec) + if err != nil { + return nil, err + } + log.GetLogger().Debug("boundary epoch", "prevLast", boundaryEpochs.PrevLast, "currentFirst", boundaryEpochs.CurrentFirst, "intermediates", boundaryEpochs.Intermediates) + + // Get validator set for verify headers + currentEpoch := boundaryEpochs.CurrentEpochBlockNumber(height) var currentTurnLength uint8 header.CurrentValidators, currentTurnLength, err = queryValidatorSetAndTurnLength(ctx, headerFn, currentEpoch) header.CurrentTurnLength = uint32(currentTurnLength) @@ -197,5 +211,13 @@ func withValidators(ctx context.Context, headerFn getHeaderFn, height uint64, et return nil, fmt.Errorf("ValidatorSet was not found in current epoch : number= %d : %+v", currentEpoch, err) } + previousEpoch := boundaryEpochs.PreviousEpochBlockNumber(currentEpoch) + var previousTurnLength uint8 + header.PreviousValidators, previousTurnLength, err = queryValidatorSetAndTurnLength(ctx, 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) + } + return header, nil } diff --git a/module/prover.go b/module/prover.go index e6e7f481..87bd06fb 100644 --- a/module/prover.go +++ b/module/prover.go @@ -3,13 +3,12 @@ package module import ( "context" "fmt" + "github.com/ethereum/go-ethereum/crypto" "time" "github.com/ethereum/go-ethereum/common" "github.com/hyperledger-labs/yui-relayer/log" - "github.com/ethereum/go-ethereum/crypto" - "github.com/cosmos/cosmos-sdk/codec" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" "github.com/cosmos/ibc-go/v8/modules/core/exported" @@ -139,7 +138,9 @@ func (pr *Prover) SetupHeadersForUpdateByLatestHeight(ctx context.Context, clien pr.chain.Header, clientStateLatestHeight, latestFinalizedHeader, - latestHeight) + latestHeight, + GetForkParameters(Network(pr.config.Network)), + ) } func (pr *Prover) ProveState(ctx core.QueryContext, path string, value []byte) ([]byte, clienttypes.Height, error) { @@ -228,22 +229,37 @@ func (pr *Prover) CheckRefreshRequired(ctx context.Context, counterparty core.Ch } func (pr *Prover) withValidators(ctx context.Context, height uint64, ethHeaders []*ETHHeader) (core.Header, error) { - return withValidators(ctx, pr.chain.Header, height, ethHeaders) + return withValidators(ctx, pr.chain.Header, height, ethHeaders, pr.getForkParameters()) +} + +func (pr *Prover) getForkParameters() []*ForkSpec { + return GetForkParameters(Network(pr.config.Network)) } func (pr *Prover) buildInitialState(ctx context.Context, dstHeader core.Header) (exported.ClientState, exported.ConsensusState, error) { - currentEpoch := getCurrentEpoch(dstHeader.GetHeight().GetRevisionHeight()) - currentValidators, currentTurnLength, err := queryValidatorSetAndTurnLength(ctx, pr.chain.Header, currentEpoch) - if err != nil { - return nil, nil, err + + // Last ForkSpec must have height or CreateClient is less than fork spec timestamp + forkSpecs := pr.getForkParameters() + lastForkSpec := forkSpecs[len(forkSpecs)-1] + lastForkSpecTime, ok := lastForkSpec.GetHeightOrTimestamp().(*ForkSpec_Timestamp) + if ok && lastForkSpecTime != nil { + target, err := dstHeader.(*Header).Target() + if err != nil { + return nil, nil, err + } + if MilliTimestamp(target) >= lastForkSpecTime.Timestamp { + return nil, nil, fmt.Errorf("target timestamp must be less than the last fork spec timestamp to submit height to ELC. %d, %d ", lastForkSpecTime.Timestamp, MilliTimestamp(target)) + } } - previousEpoch := getPreviousEpoch(dstHeader.GetHeight().GetRevisionHeight()) - previousValidators, previousTurnLength, err := queryValidatorSetAndTurnLength(ctx, pr.chain.Header, previousEpoch) + dstHeader, err := pr.withValidators(ctx, dstHeader.GetHeight().GetRevisionHeight(), dstHeader.(*Header).Headers) if err != nil { return nil, nil, err } - header, err := dstHeader.(*Header).Target() + + downcast := dstHeader.(*Header) + header, err := downcast.Target() + if err != nil { return nil, nil, err } @@ -262,11 +278,12 @@ func (pr *Prover) buildInitialState(ctx context.Context, dstHeader core.Header) Frozen: false, IbcStoreAddress: pr.chain.IBCAddress().Bytes(), IbcCommitmentsSlot: IBCCommitmentsSlot[:], + ForkSpecs: GetForkParameters(Network(pr.config.Network)), } consensusState := ConsensusState{ - Timestamp: header.Time, - PreviousValidatorsHash: makeEpochHash(previousValidators, previousTurnLength), - CurrentValidatorsHash: makeEpochHash(currentValidators, currentTurnLength), + Timestamp: MilliTimestamp(header), + PreviousValidatorsHash: makeEpochHash(downcast.PreviousValidators, uint8(downcast.PreviousTurnLength)), + CurrentValidatorsHash: makeEpochHash(downcast.CurrentValidators, uint8(downcast.CurrentTurnLength)), StateRoot: header.Root.Bytes(), } return &clientState, &consensusState, nil diff --git a/module/prover_test.go b/module/prover_test.go index 951900f7..39933ffc 100644 --- a/module/prover_test.go +++ b/module/prover_test.go @@ -2,13 +2,11 @@ package module import ( "context" + "github.com/hyperledger-labs/yui-relayer/log" "math/big" "testing" "time" - "github.com/datachainlab/ibc-hd-signer/pkg/hd" - "github.com/hyperledger-labs/yui-relayer/log" - codectypes "github.com/cosmos/cosmos-sdk/codec/types" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" conntypes "github.com/cosmos/ibc-go/v8/modules/core/03-connection/types" @@ -17,6 +15,7 @@ import ( "github.com/cosmos/ibc-go/v8/modules/core/exported" "github.com/datachainlab/ethereum-ibc-relay-chain/pkg/client" "github.com/datachainlab/ethereum-ibc-relay-chain/pkg/relay/ethereum" + "github.com/datachainlab/ibc-hd-signer/pkg/hd" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/rlp" "github.com/hyperledger-labs/yui-relayer/core" @@ -133,6 +132,7 @@ func (ts *ProverTestSuite) SetupTest() { Numerator: 1, Denominator: 2, }, + Network: string(Localnet), } ts.chain = &mockChain{ Chain: NewChain(chain), diff --git a/module/setup.go b/module/setup.go index 689fa600..b7279900 100644 --- a/module/setup.go +++ b/module/setup.go @@ -6,13 +6,51 @@ import ( clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" "github.com/cosmos/ibc-go/v8/modules/core/exported" - "github.com/datachainlab/ibc-parlia-relay/module/constant" "github.com/hyperledger-labs/yui-relayer/core" "github.com/hyperledger-labs/yui-relayer/log" ) +// Maximum header interval to be submitted to LCP +const skip = 100 + type queryVerifiableNeighboringEpochHeaderFn = func(context.Context, uint64, uint64) (core.Header, error) +func shouldSubmitBoundaryTimestampHeader( + getHeader getHeaderFn, + trustedBlockNumber uint64, + latestFinalizedBlockNumber uint64, + forkSpecs []*ForkSpec) (*uint64, uint64, error) { + + trustedBlock, err := getHeader(context.Background(), trustedBlockNumber) + if err != nil { + return nil, 0, err + } + latestFinalizedBlock, err := getHeader(context.Background(), latestFinalizedBlockNumber) + if err != nil { + return nil, 0, err + } + + latestForkSpec := forkSpecs[len(forkSpecs)-1] + latestCondition := latestForkSpec.GetHeightOrTimestamp() + if x, ok := latestCondition.(*ForkSpec_Timestamp); ok { + if MilliTimestamp(trustedBlock) < x.Timestamp && x.Timestamp < MilliTimestamp(latestFinalizedBlock) { + boundaryHeight, err := GetBoundaryHeight(getHeader, latestFinalizedBlock.Number.Uint64(), *latestForkSpec) + if err != nil { + return nil, 0, err + } + // Must be right before boundary height + if boundaryHeight.Height == 0 { + return nil, 0, fmt.Errorf("boundary height not found") + } + + nextForkBoundaryHeightMinus1 := uint64(boundaryHeight.Height) - 1 + log.GetLogger().Info("ForkSpec height required", "ts", x.Timestamp, "height", boundaryHeight, "nextForkBoundaryHeightMinus1", nextForkBoundaryHeightMinus1) + return &x.Timestamp, nextForkBoundaryHeightMinus1, nil + } + } + return nil, 0, nil +} + func setupHeadersForUpdate( ctx context.Context, queryVerifiableNeighboringEpochHeader queryVerifiableNeighboringEpochHeaderFn, @@ -20,6 +58,7 @@ func setupHeadersForUpdate( clientStateLatestHeight exported.Height, latestFinalizedHeader *Header, latestHeight exported.Height, + forkSpecs []*ForkSpec, ) ([]core.Header, error) { logger := log.GetLogger() logger.Debug("setupHeadersForUpdate start", "target", latestFinalizedHeader.GetHeight().GetRevisionHeight()) @@ -30,48 +69,67 @@ func setupHeadersForUpdate( return targetHeaders, nil } savedLatestHeight := clientStateLatestHeight.GetRevisionHeight() - firstUnsavedEpoch := toEpoch(savedLatestHeight) + constant.BlocksPerEpoch + + trustedBlock, err := getHeader(context.Background(), savedLatestHeight) + if err != nil { + return nil, err + } + + trustedCurrentForkSpec, trustedPreviousForkSpec, err := FindTargetForkSpec(forkSpecs, savedLatestHeight, MilliTimestamp(trustedBlock)) + if err != nil { + return nil, err + } + trustedBoundaryHeight, err := GetBoundaryHeight(getHeader, savedLatestHeight, *trustedCurrentForkSpec) + if err != nil { + return nil, err + } + trustedBoundaryEpochs, err := trustedBoundaryHeight.GetBoundaryEpochs(*trustedPreviousForkSpec) + if err != nil { + return nil, err + } + + trustedEpochHeight := trustedBoundaryEpochs.CurrentEpochBlockNumber(savedLatestHeight) latestFinalizedHeight := latestFinalizedHeader.GetHeight().GetRevisionHeight() - if latestFinalizedHeight < firstUnsavedEpoch { - return withTrustedHeight(append(targetHeaders, latestFinalizedHeader), clientStateLatestHeight), nil + + // If the condition is timestamp. we must submit the header with the timestamp + nextForkBoundaryTs, nextForkBoundaryHeightMinus1, err := shouldSubmitBoundaryTimestampHeader(getHeader, savedLatestHeight, latestFinalizedHeader.GetHeight().GetRevisionHeight(), forkSpecs) + if err != nil { + return nil, err } - trustedEpochHeight := toEpoch(savedLatestHeight) + firstUnsaved := trustedEpochHeight + skip + for firstUnsaved <= savedLatestHeight { + firstUnsaved += skip + } - // Append insufficient epoch blocks - for epochHeight := firstUnsavedEpoch; epochHeight < latestFinalizedHeight; epochHeight += constant.BlocksPerEpoch { - verifiableEpoch, err := setupNeighboringEpochHeader(ctx, getHeader, queryVerifiableNeighboringEpochHeader, epochHeight, trustedEpochHeight, latestHeight) + submittingHeights := makeSubmittingHeights(latestFinalizedHeight, savedLatestHeight, firstUnsaved, nextForkBoundaryTs, nextForkBoundaryHeightMinus1) + logger.Debug("submitting heights", "heights", submittingHeights, "trusted height", savedLatestHeight, "trusted epoch", trustedEpochHeight, "first unsaved", firstUnsaved) + + trustedHeight := clientStateLatestHeight.GetRevisionHeight() + for _, submittingHeight := range submittingHeights { + verifiableHeader, err := setupIntermediateHeader(ctx, queryVerifiableNeighboringEpochHeader, submittingHeight, latestHeight) if err != nil { return nil, err } - if verifiableEpoch == nil { - logger.Error("[FastFinalityError]", fmt.Errorf("insufficient vote attestation: epochHeight=%d, trustedEpochHeight=%d", epochHeight, trustedEpochHeight)) + if verifiableHeader == nil { + logger.Error("[FastFinalityError]", fmt.Errorf("insufficient vote attestation: submittingHeight=%d, trusted=%d", submittingHeight, trustedHeight)) return withTrustedHeight(targetHeaders, clientStateLatestHeight), nil } - targetHeaders = append(targetHeaders, verifiableEpoch) - trustedEpochHeight = epochHeight - logger.Debug("setup epoch header", "height", epochHeight) + targetHeaders = append(targetHeaders, verifiableHeader) + trustedHeight = submittingHeight + logger.Debug("setup epoch header", "trusted", trustedHeight, "height", submittingHeight) } return withTrustedHeight(append(targetHeaders, latestFinalizedHeader), clientStateLatestHeight), nil } -func setupNeighboringEpochHeader( +// Get verifiable headers. This method must be executed at block intervals that do not miss any epochs. +func setupIntermediateHeader( ctx context.Context, - getHeader getHeaderFn, queryVerifiableHeader queryVerifiableNeighboringEpochHeaderFn, - epochHeight uint64, - trustedEpochHeight uint64, + submittingHeight uint64, latestHeight exported.Height, ) (core.Header, error) { - // neighboring epoch needs block before checkpoint - currentValidatorSet, currentTurnLength, err := queryValidatorSetAndTurnLength(ctx, getHeader, epochHeight) - if err != nil { - return nil, fmt.Errorf("setupNeighboringEpochHeader: failed to get current validator set: epochHeight=%d : %+v", epochHeight, err) - } - // ex) trusted(prevSaved = 200), epochHeight = 400 must be finalized by min(610,latest) - nextCheckpoint := currentValidatorSet.Checkpoint(currentTurnLength) + (epochHeight + constant.BlocksPerEpoch) - limit := minUint64(nextCheckpoint-1, latestHeight.GetRevisionHeight()) - return queryVerifiableHeader(ctx, epochHeight, limit) + return queryVerifiableHeader(ctx, submittingHeight, minUint64(submittingHeight+skip, latestHeight.GetRevisionHeight())) } func withTrustedHeight(targetHeaders []core.Header, clientStateLatestHeight exported.Height) []core.Header { @@ -89,3 +147,37 @@ func withTrustedHeight(targetHeaders []core.Header, clientStateLatestHeight expo } return targetHeaders } + +func makeSubmittingHeights(latestFinalizedHeight uint64, savedLatestHeight uint64, firstUnsaved uint64, nextForkBoundaryTs *uint64, nextForkBoundaryHeightMinus1 uint64) []uint64 { + var submittingHeights []uint64 + if latestFinalizedHeight < firstUnsaved { + if nextForkBoundaryTs != nil && savedLatestHeight < nextForkBoundaryHeightMinus1 && nextForkBoundaryHeightMinus1 < latestFinalizedHeight { + submittingHeights = append(submittingHeights, nextForkBoundaryHeightMinus1) + } + } else { + var temp []uint64 + for epochCandidate := firstUnsaved; epochCandidate < latestFinalizedHeight; epochCandidate += skip { + temp = append(temp, epochCandidate) + } + if nextForkBoundaryTs != nil { + for i, epochCandidate := range temp { + if i > 0 { + if temp[i-1] < nextForkBoundaryHeightMinus1 && nextForkBoundaryHeightMinus1 < epochCandidate { + submittingHeights = append(submittingHeights, nextForkBoundaryHeightMinus1) + } + } else if i == 0 { + if savedLatestHeight < nextForkBoundaryHeightMinus1 && nextForkBoundaryHeightMinus1 < epochCandidate { + submittingHeights = append(submittingHeights, nextForkBoundaryHeightMinus1) + } + } + submittingHeights = append(submittingHeights, epochCandidate) + } + if submittingHeights[len(submittingHeights)-1] < nextForkBoundaryHeightMinus1 && nextForkBoundaryHeightMinus1 < latestFinalizedHeight { + submittingHeights = append(submittingHeights, nextForkBoundaryHeightMinus1) + } + } else { + submittingHeights = temp + } + } + return submittingHeights +} diff --git a/module/setup_test.go b/module/setup_test.go index 5ee37bf9..5860a0db 100644 --- a/module/setup_test.go +++ b/module/setup_test.go @@ -2,15 +2,15 @@ package module import ( "context" - "math/big" - "testing" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" - "github.com/datachainlab/ibc-parlia-relay/module/constant" 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" + "testing" + "time" ) type SetupTestSuite struct { @@ -28,8 +28,8 @@ func (ts *SetupTestSuite) SetupTest() { func (ts *SetupTestSuite) TestSuccess_setupHeadersForUpdate_neighboringEpoch() { - verify := func(latestHeight, nextHeight uint64, expected int) { - clientStateLatestHeight := clienttypes.NewHeight(0, latestHeight) + verify := func(trustedHeight, nextHeight uint64, expected int) { + clientStateLatestHeight := clienttypes.NewHeight(0, trustedHeight) target, err := newETHHeader(&types2.Header{ Number: big.NewInt(int64(nextHeight)), }) @@ -54,47 +54,47 @@ func (ts *SetupTestSuite) TestSuccess_setupHeadersForUpdate_neighboringEpoch() { }, nil } - targets, err := setupHeadersForUpdate(context.Background(), neighborFn, headerFn, clientStateLatestHeight, latestFinalizedHeader, clienttypes.NewHeight(0, 100000)) + targets, err := setupHeadersForUpdate(context.Background(), neighborFn, headerFn, clientStateLatestHeight, latestFinalizedHeader, clienttypes.NewHeight(0, 100000), GetForkParameters(Localnet)) ts.Require().NoError(err) ts.Require().Len(targets, expected) for i, h := range targets { trusted := h.(*Header).TrustedHeight if i == 0 { - ts.Require().Equal(trusted.RevisionHeight, latestHeight) + ts.Require().Equal(trusted.RevisionHeight, trustedHeight) } else { ts.Require().Equal(*trusted, targets[i-1].GetHeight()) } } } - verify(0, constant.BlocksPerEpoch-1, 1) - verify(0, constant.BlocksPerEpoch, 1) - verify(0, constant.BlocksPerEpoch+1, 2) - verify(0, 10*constant.BlocksPerEpoch-1, 10) - verify(0, 10*constant.BlocksPerEpoch, 10) - verify(0, 10*constant.BlocksPerEpoch+1, 11) - verify(constant.BlocksPerEpoch-1, constant.BlocksPerEpoch-1, 0) - verify(constant.BlocksPerEpoch-1, constant.BlocksPerEpoch, 1) - verify(constant.BlocksPerEpoch-1, constant.BlocksPerEpoch+1, 2) - verify(constant.BlocksPerEpoch-1, 10*constant.BlocksPerEpoch-1, 10) - verify(constant.BlocksPerEpoch-1, 10*constant.BlocksPerEpoch, 10) - verify(constant.BlocksPerEpoch-1, 10*constant.BlocksPerEpoch+1, 11) - verify(constant.BlocksPerEpoch, constant.BlocksPerEpoch, 0) - verify(constant.BlocksPerEpoch, constant.BlocksPerEpoch+1, 1) - verify(constant.BlocksPerEpoch, 10*constant.BlocksPerEpoch-1, 9) - verify(constant.BlocksPerEpoch, 10*constant.BlocksPerEpoch, 9) - verify(constant.BlocksPerEpoch, 10*constant.BlocksPerEpoch+1, 10) - verify(constant.BlocksPerEpoch+1, constant.BlocksPerEpoch+1, 0) - verify(constant.BlocksPerEpoch+1, 10*constant.BlocksPerEpoch-1, 9) - verify(constant.BlocksPerEpoch+1, 10*constant.BlocksPerEpoch, 9) - verify(constant.BlocksPerEpoch+1, 10*constant.BlocksPerEpoch+1, 10) + verify(0, skip-1, 1) + verify(0, skip, 1) + verify(0, skip+1, 2) + verify(0, 10*skip-1, 10) + verify(0, 10*skip, 10) + verify(0, 10*skip+1, 11) + verify(skip-1, skip-1, 0) + verify(skip-1, skip, 1) + verify(skip-1, skip+1, 2) + verify(skip-1, 10*skip-1, 10) + verify(skip-1, 10*skip, 10) + verify(skip-1, 10*skip+1, 11) + verify(skip, skip, 0) + verify(skip, skip+1, 1) + verify(skip, 10*skip-1, 9) + verify(skip, 10*skip, 9) + verify(skip, 10*skip+1, 10) + verify(skip+1, skip+1, 0) + verify(skip+1, 10*skip-1, 9) + verify(skip+1, 10*skip, 9) + verify(skip+1, 10*skip+1, 10) } func (ts *SetupTestSuite) TestSuccess_setupHeadersForUpdate_allEmpty() { - verify := func(latestHeight, nextHeight uint64, expected int) { - clientStateLatestHeight := clienttypes.NewHeight(0, latestHeight) + verify := func(trustedHeight, nextHeight uint64, expected int) { + clientStateLatestHeight := clienttypes.NewHeight(0, trustedHeight) target, err := newETHHeader(&types2.Header{ Number: big.NewInt(int64(nextHeight)), }) @@ -112,56 +112,173 @@ func (ts *SetupTestSuite) TestSuccess_setupHeadersForUpdate_allEmpty() { Extra: epochHeader().Extra, }, nil } - targets, err := setupHeadersForUpdate(context.Background(), neighboringEpochFn, headerFn, clientStateLatestHeight, latestFinalizedHeader, clienttypes.NewHeight(0, 1000000)) + targets, err := setupHeadersForUpdate(context.Background(), neighboringEpochFn, headerFn, clientStateLatestHeight, latestFinalizedHeader, + clienttypes.NewHeight(0, + 1000000), GetForkParameters(Localnet)) ts.Require().NoError(err) ts.Require().Len(targets, expected) } - 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) // 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) // 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 + verify(0, skip-1, 1) + verify(0, skip, 1) + verify(0, skip+1, 0) // non neighboring + verify(0, 10*skip-1, 0) + verify(0, 10*skip, 0) // non neighboring + verify(0, 10*skip+1, 0) // non neighboring + verify(skip-1, skip-1, 0) // same + verify(skip-1, skip, 1) + verify(skip-1, skip+1, 0) // non neighboring + verify(skip-1, 10*skip-1, 0) + verify(skip-1, 10*skip, 0) // non neighboring + verify(skip-1, 10*skip+1, 0) // non neighboring + verify(skip, skip, 0) // same + verify(skip, skip+1, 1) + verify(skip, 10*skip-1, 0) // non neighboring + verify(skip, 10*skip, 0) // non neighboring + verify(skip, 10*skip+1, 0) // non neighboring + verify(skip+1, skip+1, 0) // same + verify(skip+1, 10*skip-1, 0) // non neighboring + verify(skip+1, 10*skip, 0) // non neighboring + verify(skip+1, 10*skip+1, 0) // non neighboring } -func (ts *SetupTestSuite) TestSuccess_setupNeighboringEpochHeader() { +func (ts *SetupTestSuite) TestSuccess_setupHeadersForUpdate_withHFBoundary() { - epochHeight := uint64(400) - trustedEpochHeight := uint64(200) + verify := func(trustedHeight, nextHeight uint64, expected int) { + now := time.Now() + getTime := func(height uint64) time.Time { + return now.Add(time.Duration(height) * time.Second) + } - neighboringEpochFn := func(_ context.Context, height uint64, limit uint64) (core.Header, error) { + hftime := now.Add(time.Duration(trustedHeight+(nextHeight-trustedHeight)/2) * time.Second).Unix() + forkSpecs := []*ForkSpec{ + { + // Must Set Milli timestamp + HeightOrTimestamp: &ForkSpec_Height{Height: 0}, + AdditionalHeaderItemCount: 1, + EpochLength: 200, + }, + { + HeightOrTimestamp: &ForkSpec_Timestamp{Timestamp: uint64(hftime * 1000)}, + AdditionalHeaderItemCount: 1, + EpochLength: 500, + }, + } + clientStateLatestHeight := clienttypes.NewHeight(0, trustedHeight) target, err := newETHHeader(&types2.Header{ - Number: big.NewInt(int64(limit)), + Number: big.NewInt(int64(nextHeight)), + Time: uint64(now.Unix()), }) ts.Require().NoError(err) - return &Header{ - Headers: []*ETHHeader{target}, - }, nil - } - headerFn := func(_ context.Context, height uint64) (*types2.Header, error) { - return headerByHeight(int64(height)), nil + latestFinalizedHeader := &Header{ + Headers: []*ETHHeader{target}, + CurrentValidators: [][]byte{{1}}, + PreviousValidators: [][]byte{{1}}, + } + neighborFn := func(ctx context.Context, height uint64, _ uint64) (core.Header, error) { + h, e := newETHHeader(&types2.Header{ + Number: big.NewInt(int64(height)), + Time: uint64(getTime(height).Unix()), + }) + return &Header{ + Headers: []*ETHHeader{h}, + }, e + } + headerFn := func(_ context.Context, height uint64) (*types2.Header, error) { + return &types2.Header{ + Number: big.NewInt(int64(height)), + Extra: epochHeader().Extra, + Time: uint64(getTime(height).Unix()), + }, nil + } + + targets, err := setupHeadersForUpdate(context.Background(), neighborFn, headerFn, clientStateLatestHeight, latestFinalizedHeader, clienttypes.NewHeight(0, 100000), forkSpecs) + ts.Require().NoError(err) + ts.Require().Len(targets, expected) + for i, h := range targets { + trusted := h.(*Header).TrustedHeight + if i == 0 { + ts.Require().Equal(trusted.RevisionHeight, trustedHeight) + } else { + ts.Require().Equal(*trusted, targets[i-1].GetHeight()) + } + } } - hs, err := setupNeighboringEpochHeader(context.Background(), 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(602), target.Number.Int64()) + verify(0, 10*skip-1, 10+1) + verify(0, 10*skip, 10+1) + verify(0, 10*skip+1, 11+1) + verify(skip-1, skip-1, 0) + verify(skip-1, skip, 1) + verify(skip-1, skip+1, 2) + verify(skip-1, 10*skip-1, 10+1) + verify(skip-1, 10*skip, 10+1) + verify(skip-1, 10*skip+1, 11+1) + verify(skip, skip, 0) + verify(skip, skip+1, 1) + verify(skip, 10*skip-1, 9+1) + verify(skip, 10*skip, 9+1) + verify(skip, 10*skip+1, 10+1) + verify(skip+1, skip+1, 0) + verify(skip+1, 10*skip-1, 9+1) + verify(skip+1, 10*skip, 9+1) + verify(skip+1, 10*skip+1, 10+1) + +} + +func (ts *SetupTestSuite) Test_makeSubmittingHeights() { + rq := ts.Require() + msec := uint64(0) + rq.Len(makeSubmittingHeights(10, 1, 11, nil, 0), 0) + rq.Len(makeSubmittingHeights(10, 1, 11, &msec, 11), 0) + rq.Len(makeSubmittingHeights(10, 1, 11, &msec, 9), 1) + rq.Len(makeSubmittingHeights(10, 9, 11, &msec, 9), 0) + rq.Equal( + []uint64{99, 100, 200, 300, 400, 500}, + makeSubmittingHeights(501, 0, 100, &msec, 99), + ) + rq.Equal( + []uint64{100, 200, 300, 400, 500}, + makeSubmittingHeights(501, 99, 100, &msec, 99), + ) + rq.Equal( + []uint64{100, 200, 300, 400, 500}, + makeSubmittingHeights(501, 0, 100, &msec, 100), + ) + rq.Equal( + []uint64{100, 101, 200, 300, 400, 500}, + makeSubmittingHeights(501, 0, 100, &msec, 101), + ) + rq.Equal( + []uint64{100, 200, 300, 400, 500}, + makeSubmittingHeights(501, 0, 100, nil, 101), + ) + rq.Equal( + []uint64{100, 200, 201, 300, 400, 500}, + makeSubmittingHeights(501, 0, 100, &msec, 201), + ) + rq.Equal( + []uint64{100, 200, 300, 301, 400, 500}, + makeSubmittingHeights(501, 0, 100, &msec, 301), + ) + rq.Equal( + []uint64{100, 200, 300, 400, 401, 500}, + makeSubmittingHeights(501, 0, 100, &msec, 401), + ) + rq.Equal( + []uint64{100, 200, 300, 400, 500}, + makeSubmittingHeights(501, 0, 100, nil, 401), + ) + rq.Equal( + []uint64{100, 200, 300, 400, 500}, + makeSubmittingHeights(501, 0, 100, &msec, 501), + ) + rq.Equal( + []uint64{100, 200, 300, 400, 500, 501}, + makeSubmittingHeights(502, 0, 100, &msec, 501), + ) + rq.Equal( + []uint64{100, 200, 300, 400, 500}, + makeSubmittingHeights(502, 0, 100, nil, 501), + ) } diff --git a/module/util.go b/module/util.go index f56351cc..d87b9642 100644 --- a/module/util.go +++ b/module/util.go @@ -3,30 +3,12 @@ package module import ( clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" "github.com/cosmos/ibc-go/v8/modules/core/exported" - "github.com/datachainlab/ibc-parlia-relay/module/constant" ) -func getPreviousEpoch(v uint64) uint64 { - epochCount := v / constant.BlocksPerEpoch - if epochCount == 0 { - return 0 - } - return (epochCount - 1) * constant.BlocksPerEpoch -} - -func getCurrentEpoch(v uint64) uint64 { - return toEpoch(v) -} - func toHeight(height exported.Height) clienttypes.Height { return clienttypes.NewHeight(height.GetRevisionNumber(), height.GetRevisionHeight()) } -func toEpoch(v uint64) uint64 { - epochCount := v / constant.BlocksPerEpoch - return epochCount * constant.BlocksPerEpoch -} - func minUint64(x uint64, y uint64) uint64 { if x > y { return y diff --git a/module/util_test.go b/module/util_test.go deleted file mode 100644 index 86028021..00000000 --- a/module/util_test.go +++ /dev/null @@ -1,27 +0,0 @@ -package module - -import ( - "github.com/datachainlab/ibc-parlia-relay/module/constant" - "github.com/stretchr/testify/suite" - "testing" -) - -type UtilTestSuite struct { - suite.Suite -} - -func TestUtilTestSuite(t *testing.T) { - suite.Run(t, new(UtilTestSuite)) -} - -func (ts *UtilTestSuite) SetupTest() { -} - -func (ts *UtilTestSuite) TestGetPreviousEpoch() { - ts.Require().Equal(constant.BlocksPerEpoch, getPreviousEpoch(2*constant.BlocksPerEpoch)) - ts.Require().Equal(uint64(0), getPreviousEpoch(2*constant.BlocksPerEpoch-1)) - ts.Require().Equal(uint64(0), getPreviousEpoch(constant.BlocksPerEpoch+1)) - ts.Require().Equal(uint64(0), getPreviousEpoch(constant.BlocksPerEpoch)) - ts.Require().Equal(uint64(0), getPreviousEpoch(constant.BlocksPerEpoch-1)) - ts.Require().Equal(uint64(0), getPreviousEpoch(0)) -} diff --git a/module/validator_set_test.go b/module/validator_set_test.go index 890e67c5..f99a9235 100644 --- a/module/validator_set_test.go +++ b/module/validator_set_test.go @@ -33,7 +33,7 @@ func (ts *ValidatorSetTestSuite) TestSuccessExtractValidatorSet() { validators, turnLength, err = extractValidatorSetAndTurnLength(block) ts.Require().NoError(err) ts.Require().Len(validators, 4) - ts.Require().Equal(turnLength, uint8(1)) + ts.Require().Equal(turnLength, uint8(6)) } @@ -58,7 +58,7 @@ func (ts *ValidatorSetTestSuite) TestSuccessQueryValidatorSet() { validators, turnLength, err := QueryValidatorSetAndTurnLength(context.Background(), fn, 400) ts.Require().NoError(err) ts.Require().Len(validators, 4) - ts.Require().Equal(turnLength, uint8(1)) + ts.Require().Equal(turnLength, uint8(6)) } func (ts *ValidatorSetTestSuite) TestErrorQueryValidatorSet() { diff --git a/module/vote.go b/module/vote.go index a68c0141..55f1ca4a 100644 --- a/module/vote.go +++ b/module/vote.go @@ -3,7 +3,6 @@ package module import ( "bytes" "fmt" - "github.com/datachainlab/ibc-parlia-relay/module/constant" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/rlp" @@ -39,8 +38,13 @@ func getVoteAttestationFromHeader(header *types.Header) (*VoteAttestation, error return nil, nil } + isEpoch := true + if _, _, err := extractValidatorSetAndTurnLength(header); err != nil { + isEpoch = false + } + var attestationBytes []byte - if header.Number.Uint64()%constant.BlocksPerEpoch != 0 { + if !isEpoch { attestationBytes = header.Extra[extraVanity : len(header.Extra)-extraSeal] } else { num := int(header.Extra[extraVanity]) diff --git a/module/vote_test.go b/module/vote_test.go index 1015428e..caf6490b 100644 --- a/module/vote_test.go +++ b/module/vote_test.go @@ -20,22 +20,22 @@ func (ts *VoteTestSuite) SetupTest() { } func (ts *VoteTestSuite) TestSuccessGetVoteAttestationFromHeaderEpoch() { - // 400 + // 100 header := epochHeader() vote, err := getVoteAttestationFromHeader(header) ts.Require().NoError(err) 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") + ts.Require().Equal(vote.Data.SourceHash, common.HexToHash("0x302d35ff53c930401473e5650e8169f18f1156d0127cd1bd1a3e65fe365c5efc")) + ts.Require().Equal(vote.Data.SourceNumber, header.Number.Uint64()-2) + ts.Require().Equal(vote.Data.TargetHash, common.HexToHash("0x322d19e268300c0c825ffdc22a4376232406b925a7c4be8727f9a4425818ec8a")) + ts.Require().Equal(vote.Data.TargetNumber, header.Number.Uint64()-1) + ts.Require().Equal(common.Bytes2Hex(vote.AggSignature[:]), "99f5bd42d7a4e11f283b9daa22fe1f7ae89e5260b61722ec3f57dc2b18a669e0040e42a6f81d114732c00609d4648b0d0fec3a07fb300cf49a7cf6116abb217b13a63ee6330663349e8a316c42dc04f16131445a331365d2b32bcb4d5b546c25") } func (ts *VoteTestSuite) TestErrorGetVoteAttestationFromHeaderEpochNoVote() { header := &types.Header{ Extra: common.Hex2Bytes("d98301040d846765746889676f312e32312e3132856c696e757800000299d9bc0808265da01e1a65d62b903c7b34c08cb389bf3d9996f763f030b1adcfb369c5a5df4a18e1529baffe7feaec66db3dbd1bc06810f7f6f88b7be6645418a7e2a2a3f40514c215a13e315cbfb9398a26d77a299963bf034c28f8b0183ea044211f468630233d2533b73307979c78a9486b33bb4ee04ca31a65f3e86fba804db7fe293fa643e6b72bb3821a3d9d7a717d64e6088ac937d5aacdd3e20ca963979974cd8ff90cbf097023dc8c448245ceff671e965d57d82eaf9be91478cfa0f24d2993e0c5f43a6c5a4cd99850023040d3256eb0babe89f0ea54edaa398513136612f5a334b49d766ebe3eb9f6bdc163bd2c19aa7e8cee1667851ae0c1651f01c4cf7cf2cfcf8475bff3e99cab25b05631472d53387f3321fd69d1e030bb921230dfb188826affaa39ebf1c38b190851e4db0588a3e90142c5299041fb8a0db3bb9a1fa4bdf0dae84ca37ee12a6b8c26caab775f0e007b76d76ee8823de52a1a431884c2ca930c5e72bff3803af79641cf964cc001671017f0b680f93b7dde085b24bbc67b2a562a216f903ac878c5477641328172a353f1e493cf7f5f2cf1aec83bf0c74df566a41aa7ed65ea84ea99e3849ef31887c0f880a0feb92f356f58fbd023a82f5311fc87a5883a662e9ebbbefc90bf13aa533c2438a4113804bfd447b49cd040d20bc21e49ffea6487f5638e4346ad9fc6d1ec30e28016d3892b51a7898bd354cfe78643453fd3868410da412de7f2883180d0a2840111ad2e043fa403eb04cc3c0ed356ea54a6e7015490240681b002cb63e12f65c456cafca335c730b123553e70df5322013812429e0bc31508e1f1fbf0ab312e4aaade9e022150071a1f00"), - Number: big.NewInt(43198800), + Number: big.NewInt(0), } vote, err := getVoteAttestationFromHeader(header) ts.Require().NoError(err) @@ -43,21 +43,21 @@ func (ts *VoteTestSuite) TestErrorGetVoteAttestationFromHeaderEpochNoVote() { } func (ts *VoteTestSuite) TestSuccessGetVoteAttestationFromHeaderNotEpoch() { - // 401 header := epochHeaderPlus1() vote, err := getVoteAttestationFromHeader(header) ts.Require().NoError(err) 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") + ts.Require().Equal(vote.Data.SourceHash, common.HexToHash("0x322d19e268300c0c825ffdc22a4376232406b925a7c4be8727f9a4425818ec8a")) + ts.Require().Equal(vote.Data.SourceNumber, header.Number.Uint64()-2) + ts.Require().Equal(vote.Data.TargetHash, common.HexToHash("0x3a302bedfa30dd88b82a95136a99d93ea8863a741c2201ad77a63d0f9c0c329c")) + ts.Require().Equal(vote.Data.TargetNumber, header.Number.Uint64()-1) + ts.Require().Equal(common.Bytes2Hex(vote.AggSignature[:]), "a51854c31fb60a02ba70c07eeb467be677b9548c828607f99dfd0edc80a9b25be05670b86485dd71d8fb8e19d7458a9103d942ea6b84070ed47adcd3a3f284385fc538a5f692289c3abc25372e461a54ef23100718aedf80224a1e4fe26671d3") } func (ts *VoteTestSuite) TestErrorGetVoteAttestationFromHeader() { testnetHeader := &types.Header{ - Extra: make([]byte, extraSeal+extraVanity), + Extra: make([]byte, extraSeal+extraVanity), + Number: big.NewInt(0), } vote, err := getVoteAttestationFromHeader(testnetHeader) ts.Require().Nil(vote) diff --git a/proto/ibc/lightclients/parlia/v1/parlia.proto b/proto/ibc/lightclients/parlia/v1/parlia.proto index 762a126e..e67d5e37 100644 --- a/proto/ibc/lightclients/parlia/v1/parlia.proto +++ b/proto/ibc/lightclients/parlia/v1/parlia.proto @@ -7,6 +7,16 @@ import "gogoproto/gogo.proto"; import "ibc/core/client/v1/client.proto"; import "google/protobuf/duration.proto"; +message ForkSpec { + oneof height_or_timestamp { + uint64 height = 1; + uint64 timestamp = 2; + } + uint64 additional_header_item_count = 3; + uint64 epoch_length = 4; + uint64 max_turn_length = 5; +} + message ClientState { uint64 chain_id = 1; @@ -19,6 +29,8 @@ message ClientState { google.protobuf.Duration max_clock_drift = 6 [(gogoproto.nullable) = false, (gogoproto.stdduration) = true]; bool frozen = 7; + + repeated ForkSpec fork_specs = 8; } message ETHHeader { diff --git a/proto/relayer/provers/parlia/config/config.proto b/proto/relayer/provers/parlia/config/config.proto index 844faee1..7c3e0019 100644 --- a/proto/relayer/provers/parlia/config/config.proto +++ b/proto/relayer/provers/parlia/config/config.proto @@ -14,6 +14,8 @@ message ProverConfig { // Refresh if the difference between blocks in the chain and ClientState exceeds this value. // If the value is 0, no refresh decision is made. uint64 refresh_block_difference_threshold = 4; + // Network name + string network = 5; } message Fraction { diff --git a/tests/prover_network_test.go b/tests/prover_network_test.go index 2b498a34..a7a1e6eb 100644 --- a/tests/prover_network_test.go +++ b/tests/prover_network_test.go @@ -92,14 +92,23 @@ func (ts *ProverNetworkTestSuite) TestSuccessCreateInitialLightClientState() { ts.Require().NoError(err) ts.Require().Equal(cs.GetLatestHeight().GetRevisionHeight(), header.Number.Uint64()) - cVal, cTurn, err := module.QueryValidatorSetAndTurnLength(ctx, ts.chain.Header, module.GetCurrentEpoch(header.Number.Uint64())) + forkParams := module.GetForkParameters(module.Localnet) + currentForkSpec, prevForkSpec, err := module.FindTargetForkSpec(forkParams, header.Number.Uint64(), module.MilliTimestamp(header)) ts.Require().NoError(err) - pVal, pTurn, err := module.QueryValidatorSetAndTurnLength(ctx, ts.chain.Header, module.GetPreviousEpoch(header.Number.Uint64())) + bs, err := module.GetBoundaryHeight(ts.chain.Header, header.Number.Uint64(), *currentForkSpec) + ts.Require().NoError(err) + be, err := bs.GetBoundaryEpochs(*prevForkSpec) + ts.Require().NoError(err) + + currentEpoch := be.CurrentEpochBlockNumber(header.Number.Uint64()) + cVal, cTurn, err := module.QueryValidatorSetAndTurnLength(ctx, ts.chain.Header, currentEpoch) + ts.Require().NoError(err) + pVal, pTurn, err := module.QueryValidatorSetAndTurnLength(ctx, ts.chain.Header, be.PreviousEpochBlockNumber(currentEpoch)) 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) + ts.Require().Equal(consState.Timestamp, module.MilliTimestamp(header)) ts.Require().Equal(common.BytesToHash(consState.StateRoot), header.Root) } @@ -144,6 +153,8 @@ func (ts *ProverNetworkTestSuite) makeProver(chain module.Chain) *module.Prover Numerator: 3, Denominator: 2, }, + Network: string(module.Localnet), } + ts.Require().NoError(config.Validate()) return module.NewProver(chain, &config).(*module.Prover) } diff --git a/tool/testdata/README.md b/tool/testdata/README.md index 71f7505a..e623e9e7 100644 --- a/tool/testdata/README.md +++ b/tool/testdata/README.md @@ -21,14 +21,18 @@ 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 +# src/fixture/localnet.rs success_update_client_epoch_input go run main.go update success epoch -# src/client.rs test_success_update_client_non_epoch +# src/fixture/localnet.rs success_update_client_non_epoch_input go run main.go update success latest -go run main.go update success specified --num 1000 --diff 0 +# src/fixture/localnet.rs success_update_client_continuous_input +go run main.go update success specified --num 400 -# src/client.rs test_error_update_state_non_neighboring_epoch +# src/fixture/localnet.rs error_update_client_non_neighboring_epoch_input go run main.go update error + +# src/fixture/localnet.rs headers +go run main.go header success specified --num 400 ``` diff --git a/tool/testdata/internal/common.go b/tool/testdata/internal/common.go index f3a43aa6..69efab48 100644 --- a/tool/testdata/internal/common.go +++ b/tool/testdata/internal/common.go @@ -56,6 +56,7 @@ func createProver(ctx context.Context) (*module.Prover, module.Chain, error) { config := module.ProverConfig{ TrustingPeriod: 86400 * time.Second, MaxClockDrift: 1 * time.Millisecond, + Network: string(module.Localnet), } ec := module.NewChain(chain) return module.NewProver(ec, &config).(*module.Prover), ec, nil diff --git a/tool/testdata/internal/create_client.go b/tool/testdata/internal/create_client.go index 1e639f64..aef0188b 100644 --- a/tool/testdata/internal/create_client.go +++ b/tool/testdata/internal/create_client.go @@ -17,7 +17,7 @@ func (m *createClientModule) createClientSuccessCmd() *cobra.Command { cmd := &cobra.Command{ Use: "success", RunE: func(cmd *cobra.Command, args []string) error { - prover, chain, err := createProver(cmd.Context()) + prover, _, err := createProver(cmd.Context()) if err != nil { return err } @@ -42,21 +42,13 @@ func (m *createClientModule) createClientSuccessCmd() *cobra.Command { if err != nil { return err } - currentValidatorSet, currentTurnLength, err := module.QueryValidatorSetAndTurnLength(cmd.Context(), chain.Header, module.GetCurrentEpoch(cs.GetLatestHeight().GetRevisionHeight())) - if err != nil { - return err - } - previousValidatorSet, previousTurnLength, err := module.QueryValidatorSetAndTurnLength(cmd.Context(), chain.Header, module.GetPreviousEpoch(cs.GetLatestHeight().GetRevisionHeight())) - if err != nil { - return err - } log.Println("clientState", common.Bytes2Hex(anyClientState)) log.Println("consensusState", common.Bytes2Hex(anyConsState)) log.Println("height", cs.GetLatestHeight().GetRevisionHeight()) log.Println("time", consState.GetTimestamp()) - log.Println("currentEpochHash", module.MakeEpochHash(currentValidatorSet, currentTurnLength)) - log.Println("previousEpochHash", module.MakeEpochHash(previousValidatorSet, previousTurnLength)) - log.Println("storageRoot", consState.(*module.ConsensusState).StateRoot) + log.Println("currentEpochHash", common.BytesToHash(consState.(*module.ConsensusState).CurrentValidatorsHash)) + log.Println("previousEpochHash", common.BytesToHash(consState.(*module.ConsensusState).PreviousValidatorsHash)) + log.Println("storageRoot", common.BytesToHash(consState.(*module.ConsensusState).StateRoot)) return nil }, diff --git a/tool/testdata/internal/header.go b/tool/testdata/internal/header.go index 6b091aac..b2de0609 100644 --- a/tool/testdata/internal/header.go +++ b/tool/testdata/internal/header.go @@ -5,7 +5,6 @@ import ( "log" "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" @@ -56,11 +55,9 @@ func (m *headerModule) printHeader(chain module.Chain, height uint64) error { if err != nil { return errors.WithStack(err) } - if height%constant.BlocksPerEpoch == 0 { - vals, turnLength, err := module.ExtractValidatorSetAndTurnLength(header) - if err != nil { - return errors.WithStack(err) - } + + vals, turnLength, err := module.ExtractValidatorSetAndTurnLength(header) + if err == nil { log.Println("validators = ") for _, val := range vals { log.Println(common.Bytes2Hex(val)) diff --git a/tool/testdata/internal/histroy.go b/tool/testdata/internal/histroy.go index c4b55cca..89a522d4 100644 --- a/tool/testdata/internal/histroy.go +++ b/tool/testdata/internal/histroy.go @@ -2,10 +2,6 @@ package internal import ( "context" - "log" - "os" - "time" - "github.com/cometbft/cometbft/libs/json" codectypes "github.com/cosmos/cosmos-sdk/codec/types" "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" @@ -14,6 +10,9 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/golang/protobuf/proto" "github.com/spf13/cobra" + "log" + "os" + "time" ) type historyModule struct { diff --git a/tool/testdata/internal/misbehavior.go b/tool/testdata/internal/misbehavior.go index d66d8bd2..6c537d88 100644 --- a/tool/testdata/internal/misbehavior.go +++ b/tool/testdata/internal/misbehavior.go @@ -9,7 +9,6 @@ import ( "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" "github.com/datachainlab/ethereum-ibc-relay-chain/pkg/relay/ethereum" "github.com/datachainlab/ibc-parlia-relay/module" - "github.com/datachainlab/ibc-parlia-relay/module/constant" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/rlp" "github.com/spf13/cobra" @@ -105,8 +104,21 @@ func (m *misbehaviorModule) error() *cobra.Command { 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) + + forkSpec, prev, err := module.FindTargetForkSpec(module.GetForkParameters(module.Localnet), header.GetHeight().GetRevisionHeight(), module.MilliTimestamp(target2)) + if err != nil { + return err + } + bh, err := module.GetBoundaryHeight(chain.Header, header.GetHeight().GetRevisionHeight(), *forkSpec) + if err != nil { + return err + } + be, err := bh.GetBoundaryEpochs(*prev) + if err != nil { + return err + } + currentEpochBlockNumber := be.CurrentEpochBlockNumber(header.GetHeight().GetRevisionHeight()) + log.Println("Invalid block: currentEpoch", currentEpochBlockNumber) return nil }, } diff --git a/tool/testdata/internal/update_client.go b/tool/testdata/internal/update_client.go index b47ed67c..86cd1b92 100644 --- a/tool/testdata/internal/update_client.go +++ b/tool/testdata/internal/update_client.go @@ -6,7 +6,6 @@ import ( "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/pkg/errors" "github.com/spf13/cobra" @@ -47,8 +46,12 @@ func (m *updateClientModule) success() *cobra.Command { if err != nil { return err } - epochCount := latest.GetRevisionHeight() / constant.BlocksPerEpoch - return m.printHeader(cmd.Context(), prover, chain, epochCount*constant.BlocksPerEpoch+2) + be, err := m.GetBoundaryEpoch(chain, latest.GetRevisionHeight()) + if err != nil { + return err + } + epoch := be.CurrentEpochBlockNumber(latest.GetRevisionHeight()) + return m.printHeader(cmd.Context(), prover, chain, epoch+2) }, }) var num uint64 @@ -60,8 +63,12 @@ func (m *updateClientModule) success() *cobra.Command { if err != nil { return errors.WithStack(err) } - currentEpoch := module.GetCurrentEpoch(num) - previousEpoch := module.GetPreviousEpoch(num) + be, err := m.GetBoundaryEpoch(chain, num) + if err != nil { + return err + } + currentEpoch := be.CurrentEpochBlockNumber(num) + previousEpoch := be.PreviousEpochBlockNumber(currentEpoch) validator, turnLength, err := module.QueryValidatorSetAndTurnLength(cmd.Context(), chain.Header, previousEpoch) if err != nil { return errors.WithStack(err) @@ -109,18 +116,24 @@ func (m *updateClientModule) error() *cobra.Command { if err != nil { return errors.WithStack(err) } - epoch := module.GetCurrentEpoch(latest.GetRevisionHeight()) + be, err := m.GetBoundaryEpoch(chain, latest.GetRevisionHeight()) + if err != nil { + return errors.WithStack(err) + } + epoch := be.CurrentEpochBlockNumber(latest.GetRevisionHeight()) + prevEpoch := be.PreviousEpochBlockNumber(epoch) header, err := prover.GetLatestFinalizedHeaderByLatestHeight(cmd.Context(), epoch+2) if err != nil { return errors.WithStack(err) } - updating, err := prover.SetupHeadersForUpdateByLatestHeight(cmd.Context(), types.NewHeight(0, header.GetHeight().GetRevisionNumber()-constant.BlocksPerEpoch), header.(*module.Header)) + updating, err := prover.SetupHeadersForUpdateByLatestHeight(cmd.Context(), types.NewHeight(0, prevEpoch), header.(*module.Header)) if err != nil { return errors.WithStack(err) } // non neighboring epoch - newTrustedHeight := types.NewHeight(0, header.GetHeight().GetRevisionHeight()-2*constant.BlocksPerEpoch) + prevPrevEpoch := be.PreviousEpochBlockNumber(prevEpoch) + newTrustedHeight := types.NewHeight(0, prevPrevEpoch) updating[0].(*module.Header).TrustedHeight = &newTrustedHeight pack, err := types.PackClientMessage(updating[0]) if err != nil { @@ -168,11 +181,17 @@ func (m *updateClientModule) printHeader(ctx context.Context, prover *module.Pro } trustedHeight := updating[0].(*module.Header).TrustedHeight.GetRevisionHeight() - currentValidatorSetOfTrustedHeight, currentTurnLengthOfTrustedHeight, err := module.QueryValidatorSetAndTurnLength(ctx, chain.Header, module.GetCurrentEpoch(trustedHeight)) + trustedBe, err := m.GetBoundaryEpoch(chain, trustedHeight) + if err != nil { + return err + } + currentEpoch := trustedBe.CurrentEpochBlockNumber(trustedHeight) + currentValidatorSetOfTrustedHeight, currentTurnLengthOfTrustedHeight, err := module.QueryValidatorSetAndTurnLength(ctx, chain.Header, currentEpoch) if err != nil { return err } - previousValidatorSetOfTrustedHeight, previousTurnLengthOfTrustedHeight, err := module.QueryValidatorSetAndTurnLength(ctx, chain.Header, module.GetPreviousEpoch(trustedHeight)) + previousEpoch := trustedBe.PreviousEpochBlockNumber(currentEpoch) + previousValidatorSetOfTrustedHeight, previousTurnLengthOfTrustedHeight, err := module.QueryValidatorSetAndTurnLength(ctx, chain.Header, previousEpoch) if err != nil { return err } @@ -181,19 +200,32 @@ func (m *updateClientModule) printHeader(ctx context.Context, prover *module.Pro log.Println("trustedHeight", trustedHeight) 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, newTurnLength, err := module.ExtractValidatorSetAndTurnLength(target) - if err != nil { - return err - } - log.Println("newCurrentEpochHash", common.Bytes2Hex(module.MakeEpochHash(newValidators, newTurnLength))) - } else { + newValidators, newTurnLength, err := module.ExtractValidatorSetAndTurnLength(target) + if err != nil { log.Println("newCurrentEpochHash", common.Bytes2Hex(module.MakeEpochHash(header.CurrentValidators, uint8(header.CurrentTurnLength)))) + } else { + log.Println("newCurrentEpochHash", common.Bytes2Hex(module.MakeEpochHash(newValidators, newTurnLength))) } log.Println("newPreviousEpochHash", common.Bytes2Hex(module.MakeEpochHash(header.PreviousValidators, uint8(header.PreviousTurnLength)))) return nil } +func (m *updateClientModule) GetBoundaryEpoch(chain module.Chain, height uint64) (*module.BoundaryEpochs, error) { + header, err := chain.Header(context.Background(), height) + if err != nil { + return nil, err + } + forkSpec, prev, err := module.FindTargetForkSpec(module.GetForkParameters(module.Localnet), header.Number.Uint64(), module.MilliTimestamp(header)) + if err != nil { + return nil, err + } + bh, err := module.GetBoundaryHeight(chain.Header, header.Number.Uint64(), *forkSpec) + if err != nil { + return nil, err + } + return bh.GetBoundaryEpochs(*prev) +} + func CreateUpdateClient() *cobra.Command { cmd := &cobra.Command{ Use: "update",