Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Do Not Merge] Soloseng/fix-Governance-e2e #11269

Draft
wants to merge 20 commits into
base: release/core-contracts/12
Choose a base branch
from
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
260 changes: 130 additions & 130 deletions .github/workflows/celo-monorepo.yml
Original file line number Diff line number Diff line change
@@ -160,93 +160,93 @@ jobs:
- run: yarn run prettify:diff
- run: yarn run lint

protocol-test-release:
name: Protocol Test Release
runs-on: ['self-hosted', 'monorepo-node18']
timeout-minutes: 500
needs: [install-dependencies, lint-checks]
if: |
github.base_ref == 'master' || contains(github.base_ref, 'release') || contains(github.base_ref, 'production') ||
contains(needs.install-dependencies.outputs.all_modified_files, 'packages/protocol') ||
contains(needs.install-dependencies.outputs.all_modified_files, ',package.json') ||
contains(needs.install-dependencies.outputs.all_modified_files, ',yarn.lock') ||
false
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
submodules: recursive
- name: Sync workspace
uses: ./.github/actions/sync-workspace
with:
artifacts_to_cache: ${{ needs.install-dependencies.outputs.artifacts_to_cache }}
- name: Download protocol devchain artifact
uses: dawidd6/action-download-artifact@v3
with:
workflow: protocol-devchain.yml
name: devchain-${{ env.RELEASE_TAG }}
path: packages/protocol/.tmp/devchain
- name: Copy DevChain and Build generated from released tag
run: |
BUILD_AND_DEVCHAIN_DIR=$(echo build/$(echo $RELEASE_TAG | sed -e 's/\//_/g'))
(cp -r packages/protocol/.tmp/devchain packages/protocol/$BUILD_AND_DEVCHAIN_DIR)
- name: Test against current release
run: |
echo "Comparing against $RELEASE_TAG"
BUILD_AND_DEVCHAIN_DIR=$(echo build/$(echo $RELEASE_TAG | sed -e 's/\//_/g'))
yarn --cwd packages/protocol ci:test-make-release -b $RELEASE_TAG -d $BUILD_AND_DEVCHAIN_DIR
# protocol-test-release:
# name: Protocol Test Release
# runs-on: ['self-hosted', 'monorepo-node18']
# timeout-minutes: 500
# needs: [install-dependencies, lint-checks]
# if: |
# github.base_ref == 'master' || contains(github.base_ref, 'release') || contains(github.base_ref, 'production') ||
# contains(needs.install-dependencies.outputs.all_modified_files, 'packages/protocol') ||
# contains(needs.install-dependencies.outputs.all_modified_files, ',package.json') ||
# contains(needs.install-dependencies.outputs.all_modified_files, ',yarn.lock') ||
# false
# steps:
# - uses: actions/checkout@v4
# with:
# fetch-depth: 0
# submodules: recursive
# - name: Sync workspace
# uses: ./.github/actions/sync-workspace
# with:
# artifacts_to_cache: ${{ needs.install-dependencies.outputs.artifacts_to_cache }}
# - name: Download protocol devchain artifact
# uses: dawidd6/action-download-artifact@v3
# with:
# workflow: protocol-devchain.yml
# name: devchain-${{ env.RELEASE_TAG }}
# path: packages/protocol/.tmp/devchain
# - name: Copy DevChain and Build generated from released tag
# run: |
# BUILD_AND_DEVCHAIN_DIR=$(echo build/$(echo $RELEASE_TAG | sed -e 's/\//_/g'))
# (cp -r packages/protocol/.tmp/devchain packages/protocol/$BUILD_AND_DEVCHAIN_DIR)
# - name: Test against current release
# run: |
# echo "Comparing against $RELEASE_TAG"
# BUILD_AND_DEVCHAIN_DIR=$(echo build/$(echo $RELEASE_TAG | sed -e 's/\//_/g'))
# yarn --cwd packages/protocol ci:test-make-release -b $RELEASE_TAG -d $BUILD_AND_DEVCHAIN_DIR

protocol-test-matrix:
# Keeping name short because GitHub UI does not handle long names well
name: ${{ matrix.name }}
runs-on: ['self-hosted', 'monorepo-node18']
timeout-minutes: 60
needs: [install-dependencies, lint-checks]
if: |
github.base_ref == 'master' || contains(github.base_ref, 'release') || contains(github.base_ref, 'staging') || contains(github.base_ref, 'production') ||
contains(needs.install-dependencies.outputs.all_modified_files, 'packages/protocol') ||
contains(needs.install-dependencies.outputs.all_modified_files, 'packages/typescript') ||
contains(needs.install-dependencies.outputs.all_modified_files, ',package.json') ||
contains(needs.install-dependencies.outputs.all_modified_files, ',yarn.lock') ||
false
strategy:
fail-fast: false
matrix:
include:
- name: Protocol Release Snapshots
command: |
yarn --cwd packages/protocol test:release-snapshots
if [[ $(git status packages/protocol/releaseData/versionReports --porcelain) ]]; then
git --no-pager diff packages/protocol/releaseData/versionReports
echo "There are git differences after generating release version report snapshots"
echo "If these changes are intended, update the 'releaseData/versionReports' accordingly"
exit 1
fi
- name: Protocol Common tests
command: |
yarn --cwd packages/protocol test common/
- name: Protocol Compatibility
command: |
yarn --cwd packages/protocol test compatibility/
- name: Protocol scripts test
command: |
yarn --cwd packages/protocol test:scripts
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Sync workspace
uses: ./.github/actions/sync-workspace
with:
rebuild-package: 'true'
artifacts_to_cache: ${{ needs.install-dependencies.outputs.artifacts_to_cache }}
- name: Execute matrix command for test
uses: nick-fields/retry@v3
with:
timeout_minutes: 40
max_attempts: 3
command: |
${{ matrix.command }}
# protocol-test-matrix:
# # Keeping name short because GitHub UI does not handle long names well
# name: ${{ matrix.name }}
# runs-on: ['self-hosted', 'monorepo-node18']
# timeout-minutes: 60
# needs: [install-dependencies, lint-checks]
# if: |
# github.base_ref == 'master' || contains(github.base_ref, 'release') || contains(github.base_ref, 'staging') || contains(github.base_ref, 'production') ||
# contains(needs.install-dependencies.outputs.all_modified_files, 'packages/protocol') ||
# contains(needs.install-dependencies.outputs.all_modified_files, 'packages/typescript') ||
# contains(needs.install-dependencies.outputs.all_modified_files, ',package.json') ||
# contains(needs.install-dependencies.outputs.all_modified_files, ',yarn.lock') ||
# false
# strategy:
# fail-fast: false
# matrix:
# include:
# - name: Protocol Release Snapshots
# command: |
# yarn --cwd packages/protocol test:release-snapshots
# if [[ $(git status packages/protocol/releaseData/versionReports --porcelain) ]]; then
# git --no-pager diff packages/protocol/releaseData/versionReports
# echo "There are git differences after generating release version report snapshots"
# echo "If these changes are intended, update the 'releaseData/versionReports' accordingly"
# exit 1
# fi
# - name: Protocol Common tests
# command: |
# yarn --cwd packages/protocol test common/
# - name: Protocol Compatibility
# command: |
# yarn --cwd packages/protocol test compatibility/
# - name: Protocol scripts test
# command: |
# yarn --cwd packages/protocol test:scripts
# steps:
# - uses: actions/checkout@v4
# with:
# submodules: recursive
# - name: Sync workspace
# uses: ./.github/actions/sync-workspace
# with:
# rebuild-package: 'true'
# artifacts_to_cache: ${{ needs.install-dependencies.outputs.artifacts_to_cache }}
# - name: Execute matrix command for test
# uses: nick-fields/retry@v3
# with:
# timeout_minutes: 40
# max_attempts: 3
# command: |
# ${{ matrix.command }}

end-to-end-geth-matrix:
# Keeping name short because GitHub UI does not handle long names well
@@ -266,57 +266,57 @@ jobs:
fail-fast: false
matrix:
include:
- name: Transfer test
command: |
set -e
# Forcing to load go and rust paths
export PATH="/usr/local/go/bin:$HOME/.cargo/bin:${PATH}"
cd packages/celotool
./ci_test_transfers.sh checkout ${CELO_BLOCKCHAIN_BRANCH_TO_TEST}
- name: Blockchain Parameters test
command: |
set -e
export PATH="/usr/local/go/bin:$HOME/.cargo/bin:${PATH}"
cd packages/celotool
./ci_test_blockchain_parameters.sh checkout ${CELO_BLOCKCHAIN_BRANCH_TO_TEST}
- name: Slashing test
command: |
set -e
export PATH="/usr/local/go/bin:$HOME/.cargo/bin:${PATH}"
cd packages/celotool
./ci_test_slashing.sh checkout ${CELO_BLOCKCHAIN_BRANCH_TO_TEST}
# - name: Transfer test
# command: |
# set -e
# # Forcing to load go and rust paths
# export PATH="/usr/local/go/bin:$HOME/.cargo/bin:${PATH}"
# cd packages/celotool
# ./ci_test_transfers.sh checkout ${CELO_BLOCKCHAIN_BRANCH_TO_TEST}
# - name: Blockchain Parameters test
# command: |
# set -e
# export PATH="/usr/local/go/bin:$HOME/.cargo/bin:${PATH}"
# cd packages/celotool
# ./ci_test_blockchain_parameters.sh checkout ${CELO_BLOCKCHAIN_BRANCH_TO_TEST}
# - name: Slashing test
# command: |
# set -e
# export PATH="/usr/local/go/bin:$HOME/.cargo/bin:${PATH}"
# cd packages/celotool
# ./ci_test_slashing.sh checkout ${CELO_BLOCKCHAIN_BRANCH_TO_TEST}
- name: Governance test
command: |
set -e
export PATH="/usr/local/go/bin:$HOME/.cargo/bin:${PATH}"
cd packages/celotool
./ci_test_governance.sh checkout ${CELO_BLOCKCHAIN_BRANCH_TO_TEST}
- name: Replica test
command: |
set -e
export PATH="/usr/local/go/bin:$HOME/.cargo/bin:${PATH}"
cd packages/celotool
./ci_test_replicas.sh checkout ${CELO_BLOCKCHAIN_BRANCH_TO_TEST}
- name: Sync test
command: |
set -e
export PATH="/usr/local/go/bin:$HOME/.cargo/bin:${PATH}"
cd packages/celotool
./ci_test_sync.sh checkout ${CELO_BLOCKCHAIN_BRANCH_TO_TEST}
- name: CIP35 eth compatibility test
command: |
set -e
export PATH="/usr/local/go/bin:$HOME/.cargo/bin:${PATH}"
cd packages/celotool
echo "Test is skipped because migrations somehow fail"
# ./ci_test_cip35.sh checkout ${CELO_BLOCKCHAIN_BRANCH_TO_TEST}
- name: Validator order test
command: |
set -e
export PATH="/usr/local/go/bin:$HOME/.cargo/bin:${PATH}"
cd packages/celotool
# - name: Replica test
# command: |
# set -e
# export PATH="/usr/local/go/bin:$HOME/.cargo/bin:${PATH}"
# cd packages/celotool
# ./ci_test_replicas.sh checkout ${CELO_BLOCKCHAIN_BRANCH_TO_TEST}
# - name: Sync test
# command: |
# set -e
# export PATH="/usr/local/go/bin:$HOME/.cargo/bin:${PATH}"
# cd packages/celotool
# ./ci_test_sync.sh checkout ${CELO_BLOCKCHAIN_BRANCH_TO_TEST}
# - name: CIP35 eth compatibility test
# command: |
# set -e
# export PATH="/usr/local/go/bin:$HOME/.cargo/bin:${PATH}"
# cd packages/celotool
# echo "Test is skipped because migrations somehow fail"
# # ./ci_test_cip35.sh checkout ${CELO_BLOCKCHAIN_BRANCH_TO_TEST}
# - name: Validator order test
# command: |
# set -e
# export PATH="/usr/local/go/bin:$HOME/.cargo/bin:${PATH}"
# cd packages/celotool

./ci_test_validator_order.sh checkout ${CELO_BLOCKCHAIN_BRANCH_TO_TEST}
# ./ci_test_validator_order.sh checkout ${CELO_BLOCKCHAIN_BRANCH_TO_TEST}
steps:
- uses: actions/checkout@v4
with:
43 changes: 39 additions & 4 deletions packages/celotool/src/e2e-tests/governance_tests.ts
Original file line number Diff line number Diff line change
@@ -287,10 +287,12 @@ describe('governance tests', () => {
const groupInfo = await validators.methods
.getValidatorGroup(groupAddress)
.call({}, blockNumber)
console.log(`### Got memberAccounts when given blockNumber: ${groupInfo[0]}`)
return groupInfo[0]
} else {
const [groupAddress] = await validators.methods.getRegisteredValidatorGroups().call()
const groupInfo = await validators.methods.getValidatorGroup(groupAddress).call()
console.log(`### Got memberAccounts without blockNumber: ${groupInfo[0]}`)
return groupInfo[0]
}
}
@@ -310,7 +312,7 @@ describe('governance tests', () => {
if (myceloAddress === groupAddress) {
return '0x' + generatePrivateKey(mnemonic, AccountType.VALIDATOR_GROUP, 0)
}
// Otherwise, the validator group key is encoded in its name (see 25_elect_validators.ts)
// Otherwise, the validator group key is encoded in its name (see 30_elect_validators.ts)
const name = await accounts.methods.getName(groupAddress).call()
const encryptedKeystore64 = name.split(' ')[1]
const encryptedKeystore = JSON.parse(Buffer.from(encryptedKeystore64, 'base64').toString())
@@ -442,18 +444,23 @@ describe('governance tests', () => {

// groupKit uses a different node than kit does, so wait a second in case kit's node
// got the new block before groupKit's node did.
await sleep(1)
await sleep(5)
const txos = await (await groupKit.contracts.getElection()).activate(group)
for (const txo of txos) {
await txo.sendAndWaitForReceipt({ from: group })
}

const validatorSetSigners0 = await election.methods.getCurrentValidatorSigners().call()
console.log(`### current block: ${await groupKit.connection.getBlockNumber()}`)
console.log(`### Got _validatorSetSigners0: ${validatorSetSigners0}`)
validators = await groupKit._web3Contracts.getValidators()
const membersToSwap = [validatorAccounts[0], validatorAccounts[1]]
const memberSwapper = await newMemberSwapper(groupKit, membersToSwap)
// The memberSwapper makes a change when it's created, so we wait for epoch change so it takes effect
await waitForEpochTransition(web3, epoch)

const validatorSetSigners1 = await election.methods.getCurrentValidatorSigners().call()
console.log(`### Got _validatorSetSigners1: ${validatorSetSigners1}`)
console.log(`### current block: ${await groupKit.connection.getBlockNumber()}`)
const handled: any = {}

let errorWhileChangingValidatorSet = ''
@@ -470,6 +477,7 @@ describe('governance tests', () => {
// 1. Swap validator0 and validator1 so one is a member of the group and the other is not.
// 2. Rotate keys for validator 2 by authorizing a new validating key.
await memberSwapper.swap()
console.log(`### swapped members at block: ${header.number}`)
}
} catch (e: any) {
console.error(e)
@@ -485,6 +493,7 @@ describe('governance tests', () => {
// Prepare for member swapping.
await sleep(epoch)
}
console.log(`### current block after 40 block: ${await groupKit.connection.getBlockNumber()}`)
;(subscription as any).unsubscribe()

// Wait for the current epoch to complete.
@@ -498,6 +507,7 @@ describe('governance tests', () => {

const getValidatorSetAccountsAtBlock = async (blockNumber: number) => {
const signingKeys = await getValidatorSetSignersAtBlock(blockNumber)
console.log(`### Got signingKeys: ${signingKeys}`)
return Promise.all(
signingKeys.map((address: string) =>
accounts.methods.signerToAccount(address).call({}, blockNumber)
@@ -507,6 +517,7 @@ describe('governance tests', () => {

it('should always return a validator set size equal to the number of group members at the end of the last epoch', async () => {
for (const blockNumber of blockNumbers) {
console.log(`### blockNumber: ${blockNumber}`)
const lastEpochBlock = getLastEpochBlock(blockNumber, epoch)
const validatorSetSize = await election.methods
.numberValidatorsInCurrentSet()
@@ -515,17 +526,39 @@ describe('governance tests', () => {
assert.equal(validatorSetSize, groupMembership.length)
}
})

// TODO (soloseng) fix test such that it returns expected validators
it('should always return a validator set equal to the signing keys of the group members at the end of the last epoch', async function (this: any) {
this.timeout(0)
for (const blockNumber of blockNumbers) {
console.log(`### here`)
const minElected = await election.methods.electableValidators().call({}, blockNumber)
console.log(`### minElected: ${JSON.stringify(minElected, null, 2)}`)

const lastEpochBlock = getLastEpochBlock(blockNumber, epoch)
const memberAccounts = await getValidatorGroupMembers(lastEpochBlock)
console.log(`### Got memberAccounts: ${memberAccounts}`)

const signer0 = await election.methods
.validatorSignerAddressFromCurrentSet(0)
.call({}, blockNumber)

const signer1 = await election.methods
.validatorSignerAddressFromCurrentSet(1)
.call({}, blockNumber)

console.log(`### Got signer0: ${signer0}`)
console.log(`### Got signer1: ${signer1}`)
const memberSigners = await Promise.all(
memberAccounts.map((v: string) => getValidatorSigner(v, lastEpochBlock))
)
console.log(`### Got memberSigners: ${memberSigners}`)

const validatorSetSigners = await getValidatorSetSignersAtBlock(blockNumber)
console.log(`### Got validatorSetSigners at ${blockNumber}: ${validatorSetSigners}`)

const validatorSetAccounts = await getValidatorSetAccountsAtBlock(blockNumber)
console.log(`### Got validatorSetAccounts: ${validatorSetAccounts}`)

assert.sameMembers(memberSigners, validatorSetSigners)
assert.sameMembers(memberAccounts, validatorSetAccounts)
}
@@ -538,11 +571,13 @@ describe('governance tests', () => {
// Fetch the round robin order if it hasn't already been set for this epoch.
if (roundRobinOrder.length === 0 || blockNumber === lastEpochBlock + 1) {
const validatorSet = await getValidatorSetSignersAtBlock(blockNumber)
console.log(`### validatorSet: ${validatorSet}`)
roundRobinOrder = await Promise.all(
validatorSet.map(
async (_, i) => (await web3.eth.getBlock(lastEpochBlock + i + 1)).miner
)
)
console.log(`### roundRobinOrder: ${roundRobinOrder}`)
assert.sameMembers(roundRobinOrder, validatorSet)
}
const indexInEpoch = blockNumber - lastEpochBlock - 1
2 changes: 1 addition & 1 deletion packages/celotool/src/lib/geth.ts
Original file line number Diff line number Diff line change
@@ -1477,7 +1477,7 @@ export async function writeGenesisWithMigrations(
const genesisPath = path.join(gethConfig.runPath, 'genesis.json')

if (verbose) {
console.info('writing genesis')
console.info('writing genesis with migrations')
}

fs.writeFileSync(genesisPath, genesis)
Original file line number Diff line number Diff line change
@@ -42,7 +42,7 @@ contract PrecompilesOverride is UsingPrecompiles, UsingRegistry {
if (isL2()) {
return getEpochManager().getElectedSignerByIndex(index);
} else {
super.validatorSignerAddressFromCurrentSet(index);
return super.validatorSignerAddressFromCurrentSet(index);
}
}

2 changes: 1 addition & 1 deletion packages/protocol/package.json
Original file line number Diff line number Diff line change
@@ -152,4 +152,4 @@
"typechain-target-ethers-v5": "^5.0.1",
"yargs": "^14.0.0"
}
}
}
5 changes: 4 additions & 1 deletion packages/protocol/scripts/truffle/make-release.ts
Original file line number Diff line number Diff line change
@@ -112,7 +112,7 @@ const deployImplementation = async (
if (from) {
Contract.defaults({ from }) // override truffle with provided from address
}
console.info(`Deploying ${contractName}`)
console.info(`Deploying implementation: ${contractName}`)
// Hack to trick truffle, which checks that the provided address has code

// without this delay it sometimes fails with ProviderError
@@ -188,6 +188,7 @@ const deployCoreContract = async (
isDryRun: boolean,
from: string
) => {
console.log(`Deploying core contract: ${contractName}`)
const contract = await deployImplementation(contractName, instance, isDryRun, from)
const setImplementationTx: ProposalTx = {
contract: `${contractName}Proxy`,
@@ -211,6 +212,8 @@ const deployCoreContract = async (
description: `Registry: ${contractName} -> ${proxy.address}`,
})

console.log(`propose set to registry`)

// If the implementation has an initialize function, add it to the proposal
const initializeAbi = (contract as any).abi.find(
(abi: any) => abi.type === 'function' && abi.name === 'initialize'