From 56de7fbc64cc69738d910d0ead8a261ed9790a9b Mon Sep 17 00:00:00 2001 From: Noam Berg Date: Mon, 10 Feb 2020 15:47:31 +0200 Subject: [PATCH 1/2] add locked stake to the election contract -> read it during "getstake" of each actor - in orbs save sum. --- go.mod | 1 - .../repository/_Elections/ethereum_binding.go | 9 +++ .../native/repository/_Elections/exports.go | 12 ++- .../_Elections/exports_unsafetests.go | 13 +++- .../repository/_Elections/harness_test.go | 53 +++++++++---- .../repository/_Elections/helpers_test.go | 1 + .../repository/_Elections/processing_vote.go | 25 ++++-- .../_Elections/processing_vote_test.go | 78 +++++++++++++++++-- 8 files changed, 151 insertions(+), 41 deletions(-) diff --git a/go.mod b/go.mod index 50ecd5f32..0dde62ff7 100644 --- a/go.mod +++ b/go.mod @@ -17,7 +17,6 @@ require ( github.com/ethereum/go-ethereum v1.9.6 github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 // indirect github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff // indirect - github.com/go-stack/stack v1.8.0 // indirect github.com/google/go-cmp v0.3.1 github.com/huin/goupnp v1.0.0 // indirect github.com/jackpal/go-nat-pmp v1.0.1 // indirect diff --git a/services/processor/native/repository/_Elections/ethereum_binding.go b/services/processor/native/repository/_Elections/ethereum_binding.go index 2064d2498..162736c25 100644 --- a/services/processor/native/repository/_Elections/ethereum_binding.go +++ b/services/processor/native/repository/_Elections/ethereum_binding.go @@ -10,6 +10,7 @@ package elections_systemcontract * Connections to Ethereum contracts */ var ETHEREUM_TOKEN_ADDR = "0xff56Cc6b1E6dEd347aA0B7676C85AB0B3D08B0FA" +var ETHEREUM_STAKING_ADDR = "0xff56Cc6b1E6dEd347aA0B7676C85AB0B3D08B0FA" // TODO LOCKING replace with actual contract address var ETHEREUM_VOTING_ADDR = "0x30f855afb78758Aa4C2dc706fb0fA3A98c865d2d" var ETHEREUM_VALIDATORS_ADDR = "0x240fAa45557c61B6959162660E324Bb90984F00f" var ETHEREUM_VALIDATORS_REGISTRY_ADDR = "0x56A6895FD37f358c17cbb3F14A864ea5Fe871F0a" @@ -23,6 +24,14 @@ func getTokenAbi() string { return `[{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"owner","type":"address"},{"indexed":true,"name":"spender","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"constant":false,"inputs":[{"name":"to","type":"address"},{"name":"value","type":"uint256"}],"name":"transfer","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"spender","type":"address"},{"name":"value","type":"uint256"}],"name":"approve","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"from","type":"address"},{"name":"to","type":"address"},{"name":"value","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"who","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"owner","type":"address"},{"name":"spender","type":"address"}],"name":"allowance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"}]` } +func getStakingEthereumContractAddress() string { + return ETHEREUM_STAKING_ADDR +} + +func getStakingAbi() string { + return `[{"anonymous":false,"inputs":[{"indexed":true,"name":"stakeOwner","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"totalStakedAmount","type":"uint256"}],"name":"Staked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"stakeOwner","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"totalStakedAmount","type":"uint256"}],"name":"Unstaked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"stakeOwner","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"totalStakedAmount","type":"uint256"}],"name":"Withdrew","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"stakeOwner","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"totalStakedAmount","type":"uint256"}],"name":"Restaked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"stakeOwner","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"totalStakedAmount","type":"uint256"}],"name":"MigratedStake","type":"event"},{"constant":false,"inputs":[{"name":"_amount","type":"uint256"}],"name":"stake","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_amount","type":"uint256"}],"name":"unstake","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"withdraw","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"restake","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_totalAmount","type":"uint256"},{"name":"_stakeOwners","type":"address[]"},{"name":"_amounts","type":"uint256[]"}],"name":"distributeRewards","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_stakeOwner","type":"address"}],"name":"getStakeBalanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getTotalStakedTokens","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_stakeOwner","type":"address"}],"name":"getUnstakeStatus","outputs":[{"name":"cooldownAmount","type":"uint256"},{"name":"cooldownEndTime","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_newStakingContract","type":"address"},{"name":"_amount","type":"uint256"}],"name":"migrateStakedTokens","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"}]` +} + func getGuardiansEthereumContractAddress() string { return ETHEREUM_GUARDIANS_ADDR } diff --git a/services/processor/native/repository/_Elections/exports.go b/services/processor/native/repository/_Elections/exports.go index 4a38238f1..dcda01936 100644 --- a/services/processor/native/repository/_Elections/exports.go +++ b/services/processor/native/repository/_Elections/exports.go @@ -12,24 +12,22 @@ import ( "github.com/orbs-network/orbs-contract-sdk/go/sdk/v1" ) -var PUBLIC = sdk.Export(getTokenEthereumContractAddress, getGuardiansEthereumContractAddress, getVotingEthereumContractAddress, getValidatorsEthereumContractAddress, getValidatorsRegistryEthereumContractAddress, +var PUBLIC = sdk.Export(getTokenEthereumContractAddress, getStakingEthereumContractAddress, getGuardiansEthereumContractAddress, getVotingEthereumContractAddress, getValidatorsEthereumContractAddress, getValidatorsRegistryEthereumContractAddress, mirrorDelegationByTransfer, mirrorDelegation, processVoting, isProcessingPeriod, hasProcessingStarted, processTrigger, getNumberOfElections, isElectionOverdue, - getElectionPeriodInNanos, getEffectiveElectionTimeInNanos, getCurrentElectionTimeInNanos, getNextElectionTimeInNanos, getElectedValidatorsOrbsAddress, getElectedValidatorsEthereumAddress, getElectedValidatorsEthereumAddressByBlockNumber, getElectedValidatorsOrbsAddressByBlockHeight, getElectedValidatorsOrbsAddressByIndex, getElectedValidatorsEthereumAddressByIndex, getElectedValidatorsBlockNumberByIndex, getElectedValidatorsBlockHeightByIndex, getCumulativeParticipationReward, getCumulativeGuardianExcellenceReward, getCumulativeValidatorReward, getGuardianStake, getGuardianVotingWeight, getTotalStake, getValidatorStake, getValidatorVote, getExcellenceProgramGuardians, getCurrentEthereumBlockNumber, - _fixRewardsDrift9108900, - - // feature flag - switchToTimeBasedElections, - // block based getElectionPeriod, getCurrentElectionBlockNumber, getNextElectionBlockNumber, getEffectiveElectionBlockNumber, getProcessingStartBlockNumber, getMirroringEndBlockNumber, + + // time base + //switchToTimeBasedElections, + //getElectionPeriodInNanos, getEffectiveElectionTimeInNanos, getCurrentElectionTimeInNanos, getNextElectionTimeInNanos, ) var SYSTEM = sdk.Export(_init) diff --git a/services/processor/native/repository/_Elections/exports_unsafetests.go b/services/processor/native/repository/_Elections/exports_unsafetests.go index 095f80923..25ad860cc 100644 --- a/services/processor/native/repository/_Elections/exports_unsafetests.go +++ b/services/processor/native/repository/_Elections/exports_unsafetests.go @@ -17,21 +17,22 @@ import ( "time" ) -var PUBLIC = sdk.Export(getTokenEthereumContractAddress, getGuardiansEthereumContractAddress, getVotingEthereumContractAddress, getValidatorsEthereumContractAddress, getValidatorsRegistryEthereumContractAddress, - unsafetests_setTokenEthereumContractAddress, unsafetests_setGuardiansEthereumContractAddress, +var PUBLIC = sdk.Export(getTokenEthereumContractAddress, getStakingEthereumContractAddress, getGuardiansEthereumContractAddress, getVotingEthereumContractAddress, getValidatorsEthereumContractAddress, getValidatorsRegistryEthereumContractAddress, + unsafetests_setTokenEthereumContractAddress, unsafetests_setStakingEthereumContractAddress, unsafetests_setGuardiansEthereumContractAddress, unsafetests_setVotingEthereumContractAddress, unsafetests_setValidatorsEthereumContractAddress, unsafetests_setValidatorsRegistryEthereumContractAddress, unsafetests_setVariables, unsafetests_setElectedValidators, unsafetests_setCurrentElectedBlockNumber, unsafetests_setCurrentElectionTimeNanos, unsafetests_setElectionMirrorPeriodInSeconds, unsafetests_setElectionVotePeriodInSeconds, unsafetests_setElectionPeriodInSeconds, mirrorDelegationByTransfer, mirrorDelegation, processVoting, isProcessingPeriod, hasProcessingStarted, processTrigger, getElectionPeriod, getCurrentElectionBlockNumber, getNextElectionBlockNumber, getEffectiveElectionBlockNumber, getNumberOfElections, - getElectionPeriodInNanos, getEffectiveElectionTimeInNanos, getCurrentElectionTimeInNanos, getNextElectionTimeInNanos, getCurrentEthereumBlockNumber, getProcessingStartBlockNumber, isElectionOverdue, getMirroringEndBlockNumber, getElectedValidatorsOrbsAddress, getElectedValidatorsEthereumAddress, getElectedValidatorsEthereumAddressByBlockNumber, getElectedValidatorsOrbsAddressByBlockHeight, getElectedValidatorsOrbsAddressByIndex, getElectedValidatorsEthereumAddressByIndex, getElectedValidatorsBlockNumberByIndex, getElectedValidatorsBlockHeightByIndex, getCumulativeParticipationReward, getCumulativeGuardianExcellenceReward, getCumulativeValidatorReward, getGuardianStake, getGuardianVotingWeight, getTotalStake, getValidatorStake, getValidatorVote, getExcellenceProgramGuardians, - switchToTimeBasedElections, + // time based + // switchToTimeBasedElections, + //getElectionPeriodInNanos, getEffectiveElectionTimeInNanos, getCurrentElectionTimeInNanos, getNextElectionTimeInNanos, ) var SYSTEM = sdk.Export(_init) @@ -64,6 +65,10 @@ func unsafetests_setTokenEthereumContractAddress(addr string) { ETHEREUM_TOKEN_ADDR = addr } +func unsafetests_setStakingEthereumContractAddress(addr string) { + ETHEREUM_STAKING_ADDR = addr +} + func unsafetests_setVotingEthereumContractAddress(addr string) { ETHEREUM_VOTING_ADDR = addr } diff --git a/services/processor/native/repository/_Elections/harness_test.go b/services/processor/native/repository/_Elections/harness_test.go index a191441c2..5e75bd402 100644 --- a/services/processor/native/repository/_Elections/harness_test.go +++ b/services/processor/native/repository/_Elections/harness_test.go @@ -37,6 +37,7 @@ type harness struct { type actor struct { stake int + lockedStake int address [20]byte } @@ -52,14 +53,9 @@ func (g *guardian) withIsGuardian(isGuardian bool) *guardian { return g } -type delegator struct { - actor - delegate [20]byte -} - -type validator struct { - actor - orbsAddress [20]byte +func (g *guardian) vote(asOfBlock uint64, validators ...*validator) { + g.voteBlock = asOfBlock + g.votedValidators = getValidatorAddresses(validators) } func getValidatorAddresses(validatorObjs []*validator) [][20]byte { @@ -69,9 +65,20 @@ func getValidatorAddresses(validatorObjs []*validator) [][20]byte { } return addresses } -func (g *guardian) vote(asOfBlock uint64, validators ...*validator) { - g.voteBlock = asOfBlock - g.votedValidators = getValidatorAddresses(validators) + +type delegator struct { + actor + delegate [20]byte +} + +func (d *delegator) withLockedStake(lockedStake int) *delegator { + d.lockedStake = lockedStake + return d +} + +type validator struct { + actor + orbsAddress [20]byte } func newHarness(isTime bool) *harness { @@ -182,7 +189,7 @@ func (f *harness) setupEthereumStateBeforeProcess(m Mockery) { f.setupEthereumGuardiansDataBeforeProcess(m) for _, d := range f.delegators { - mockStakeInEthereum(m, f.electionBlock, d.address, d.stake) + mockStakedAndLockedInEthereum(m, f.electionBlock, d.address, d.stake, d.lockedStake) } } @@ -191,7 +198,7 @@ func (f *harness) setupEthereumGuardiansDataBeforeProcess(m Mockery) { if a.isGuardian { mockGuardianVoteInEthereum(m, f.electionBlock, a.address, a.votedValidators, a.voteBlock) if a.voteBlock >= _getProcessCurrentElectionEarliestValidVoteBlockNumber() { - mockStakeInEthereum(m, f.electionBlock, a.address, a.stake) + mockStakedAndLockedInEthereum(m, f.electionBlock, a.address, a.stake, a.lockedStake) } } } @@ -202,7 +209,7 @@ func (f *harness) setupEthereumValidatorsBeforeProcess(m Mockery) { validatorAddresses := make([][20]byte, len(f.validators)) for i, a := range f.validators { validatorAddresses[i] = a.address - mockStakeInEthereum(m, f.electionBlock, a.address, a.stake) + mockStakedAndLockedInEthereum(m, f.electionBlock, a.address, a.stake, a.lockedStake) mockValidatorOrbsAddressInEthereum(m, f.electionBlock, a.address, a.orbsAddress) } mockValidatorsInEthereum(m, f.electionBlock, validatorAddresses) @@ -289,6 +296,11 @@ func mockValidatorOrbsAddressInEthereum(m Mockery, blockNumber uint64, validator }, validatorAddress) } +func mockStakedAndLockedInEthereum(m Mockery, blockNumber uint64, address [20]byte, stake int, lockedStake int) { + mockStakeInEthereum(m, blockNumber, address, stake) + mockLockedStakeInEthereum(m, blockNumber, address, lockedStake) +} + func mockStakeInEthereum(m Mockery, blockNumber uint64, address [20]byte, stake int) { stakeValue := big.NewInt(int64(stake)) stakeValue = stakeValue.Mul(stakeValue, ETHEREUM_STAKE_FACTOR) @@ -302,6 +314,19 @@ func mockStakeInEthereum(m Mockery, blockNumber uint64, address [20]byte, stake }, address) } +func mockLockedStakeInEthereum(m Mockery, blockNumber uint64, address [20]byte, stake int) { + stakeValue := big.NewInt(int64(stake)) + stakeValue = stakeValue.Mul(stakeValue, ETHEREUM_STAKE_FACTOR) + m.MockEthereumCallMethodAtBlock(blockNumber, getStakingEthereumContractAddress(), getStakingAbi(), "getStakeBalanceOf", func(out interface{}) { + i, ok := out.(**big.Int) + if ok { + *i = stakeValue + } else { + panic(fmt.Sprintf("wrong something %s", out)) + } + }, address) +} + func startTimeBasedGetElectionTime() uint64 { switchToTimeBasedElections() electionDate := 2 * ELECTION_PERIOD_LENGTH_IN_NANOS diff --git a/services/processor/native/repository/_Elections/helpers_test.go b/services/processor/native/repository/_Elections/helpers_test.go index 0b324c800..1e34d7cf6 100644 --- a/services/processor/native/repository/_Elections/helpers_test.go +++ b/services/processor/native/repository/_Elections/helpers_test.go @@ -7,6 +7,7 @@ import ( ) func TestOrbsVotingContract_initCurrentElection(t *testing.T) { + t.Skip() tests := []struct { name string expectCurrentTime uint64 diff --git a/services/processor/native/repository/_Elections/processing_vote.go b/services/processor/native/repository/_Elections/processing_vote.go index 15ccf92e6..ea4525cfb 100644 --- a/services/processor/native/repository/_Elections/processing_vote.go +++ b/services/processor/native/repository/_Elections/processing_vote.go @@ -117,10 +117,11 @@ func _collectOneValidatorDataFromEthereum(i int) { var orbsAddress [20]byte ethereum.CallMethodAtBlock(_getProcessCurrentElectionBlockNumber(), getValidatorsRegistryEthereumContractAddress(), getValidatorsRegistryAbi(), "getOrbsAddress", &orbsAddress, validator) stake := _getStakeAtElection(validator) + lockedStake := _getLockedStakeAtElection(validator) - _setValidatorStake(validator[:], stake) + _setValidatorStake(validator[:], safeuint64.Add(stake, lockedStake)) _setValidatorOrbsAddress(validator[:], orbsAddress[:]) - fmt.Printf("elections %10d: from ethereum validator %x, stake %d orbsAddress %x\n", _getProcessCurrentElectionBlockNumber(), validator, stake, orbsAddress) + fmt.Printf("elections %10d: from ethereum validator %x, unlocked-stake %d, locked-stake %d, orbsAddress %x\n", _getProcessCurrentElectionBlockNumber(), validator, stake, lockedStake, orbsAddress) } func _collectNextGuardiansDataFromEthereum() bool { @@ -139,6 +140,7 @@ type Vote struct { func _collectOneGuardianDataFromEthereum(i int) { guardian := _getGuardianAtIndex(i) stake := uint64(0) + lockedStake := uint64(0) candidates := [][20]byte{{}} out := Vote{} @@ -146,15 +148,16 @@ func _collectOneGuardianDataFromEthereum(i int) { voteBlockNumber := out.BlockNumber.Uint64() if voteBlockNumber != 0 && voteBlockNumber >= _getProcessCurrentElectionEarliestValidVoteBlockNumber() { stake = _getStakeAtElection(guardian) + lockedStake = _getLockedStakeAtElection(guardian) candidates = out.ValidatorsBytes20 voteBlockNumber = out.BlockNumber.Uint64() - fmt.Printf("elections %10d: from ethereum guardian %x voted at %d, stake %d\n", _getProcessCurrentElectionBlockNumber(), guardian, voteBlockNumber, stake) + fmt.Printf("elections %10d: from ethereum guardian %x voted at %d, unlocked-stake %d, locked-stake %d\n", _getProcessCurrentElectionBlockNumber(), guardian, voteBlockNumber, stake, lockedStake) } else { voteBlockNumber = uint64(0) fmt.Printf("elections %10d: from ethereum guardian %x vote is too old, will ignore\n", _getProcessCurrentElectionBlockNumber(), guardian) } - _setGuardianStake(guardian[:], stake) + _setGuardianStake(guardian[:], safeuint64.Add(stake, lockedStake)) _setGuardianVoteBlockNumber(guardian[:], voteBlockNumber) _setCandidates(guardian[:], candidates) } @@ -170,13 +173,15 @@ func _collectNextDelegatorStakeFromEthereum() bool { func _collectOneDelegatorStakeFromEthereum(i int) { delegator := _getDelegatorAtIndex(i) stake := uint64(0) + lockedStake := uint64(0) if !_isGuardian(delegator) { stake = _getStakeAtElection(delegator) + lockedStake = _getLockedStakeAtElection(delegator) } else { fmt.Printf("elections %10d: from ethereum delegator %x is actually a guardian, will ignore\n", _getProcessCurrentElectionBlockNumber(), delegator) } - state.WriteUint64(_formatDelegatorStakeKey(delegator[:]), stake) - fmt.Printf("elections %10d: from ethereum delegator %x , stake %d\n", _getProcessCurrentElectionBlockNumber(), delegator, stake) + state.WriteUint64(_formatDelegatorStakeKey(delegator[:]), safeuint64.Add(stake, lockedStake)) + fmt.Printf("elections %10d: from ethereum delegator %x , unlocked-stake %d, locked stake %d\n", _getProcessCurrentElectionBlockNumber(), delegator, stake, lockedStake) } func _getStakeAtElection(ethAddr [20]byte) uint64 { @@ -185,6 +190,12 @@ func _getStakeAtElection(ethAddr [20]byte) uint64 { return ((*stake).Div(*stake, ETHEREUM_STAKE_FACTOR)).Uint64() } +func _getLockedStakeAtElection(ethAddr [20]byte) uint64 { + lockedStake := new(*big.Int) + ethereum.CallMethodAtBlock(_getProcessCurrentElectionBlockNumber(), getStakingEthereumContractAddress(), getStakingAbi(), "getStakeBalanceOf", lockedStake, ethAddr) + return ((*lockedStake).Div(*lockedStake, ETHEREUM_STAKE_FACTOR)).Uint64() +} + func _calculateVotes() (candidateVotes map[[20]byte]uint64, totalVotes uint64, participants [][20]byte, participantStakes map[[20]byte]uint64, guardianAccumulatedStakes map[[20]byte]uint64) { guardians := _getGuardians() guardianStakes := _collectGuardiansStake(guardians) @@ -218,7 +229,7 @@ func _collectDelegatorsStake(guardians map[[20]byte]bool) (delegators [][20]byte for i := 0; i < numOfDelegators; i++ { delegator := _getDelegatorAtIndex(i) if !guardians[delegator] { - if _, ok := delegatorStakes[delegator]; !ok { // + if _, ok := delegatorStakes[delegator]; !ok { stake := state.ReadUint64(_formatDelegatorStakeKey(delegator[:])) delegatorStakes[delegator] = stake delegators = append(delegators, delegator) diff --git a/services/processor/native/repository/_Elections/processing_vote_test.go b/services/processor/native/repository/_Elections/processing_vote_test.go index d9c947008..ae850ce71 100644 --- a/services/processor/native/repository/_Elections/processing_vote_test.go +++ b/services/processor/native/repository/_Elections/processing_vote_test.go @@ -35,6 +35,27 @@ func TestOrbsVotingContract_getStakeFromEthereum(t *testing.T) { }) } +func TestOrbsVotingContract_getLockedStakeFromEthereum(t *testing.T) { + addr := [20]byte{0x01} + blockNumber := uint64(100) + stakeSetup := 64 + + InServiceScope(nil, nil, func(m Mockery) { + _init() + + // prepare + _setProcessCurrentElection(0, blockNumber, 0) + mockLockedStakeInEthereum(m, blockNumber, addr, stakeSetup) + + // call + stake := _getLockedStakeAtElection(addr) + + // assert + m.VerifyMocks() + require.EqualValues(t, stakeSetup, stake) + }) +} + func TestOrbsVotingContract_processVote_processVoteMachine_CalulateStakes(t *testing.T) { h := newHarnessBlockBased() h.electionBlock = uint64(60000) @@ -77,6 +98,46 @@ func TestOrbsVotingContract_processVote_processVoteMachine_CalulateStakes(t *tes }) } +func TestOrbsVotingContract_processVote_processVoteMachine_CalulateStakesWithLocked(t *testing.T) { + h := newHarnessBlockBased() + h.electionBlock = 60000 + aRecentVoteBlock := h.electionBlock - 1 + + var v1, v2, v3, v4, v5 = h.addValidator(), h.addValidator(), h.addValidator(), h.addValidator(), h.addValidator() + var g1, g2, g3, g4 = h.addGuardian(100), h.addGuardian(200), h.addGuardian(400), h.addGuardian(1000) + + g1.vote(aRecentVoteBlock, v2, v1) + g2.vote(aRecentVoteBlock, v2, v1) + g3.vote(aRecentVoteBlock, v2, v3) + g4.vote(aRecentVoteBlock, v2, v5) + + for i := 0; i < 10; i++ { + h.addDelegator(500, g3.address) + } + + d1 := h.addDelegator(500, g4.address).withLockedStake(100000) + d2 := h.addDelegator(500, d1.address) + h.addDelegator(500, d2.address) + + InServiceScope(nil, nil, func(m Mockery) { + _init() + + // prepare + h.setupOrbsStateBeforeProcessMachine() + h.setupEthereumStateBeforeProcess(m) + + // call + expectedNumOfStateTransitions := len(h.guardians) + len(h.delegators) + len(h.validators) + 2 + elected, actualRuns := h.runProcessVoteMachineNtimes(expectedNumOfStateTransitions) + + // assert + m.VerifyMocks() + require.True(t, actualRuns <= expectedNumOfStateTransitions, "did not finish in correct amount of passes") + require.EqualValues(t, "", _getVotingProcessState()) + require.ElementsMatch(t, [][20]byte{v1.address, v3.address, v4.address}, elected) + }) +} + func TestOrbsVotingContract_processVote_processVoteMachineWithTimeBased_CalulateStakes(t *testing.T) { h := newHarnessTimeBased() h.electionBlock = 60000 @@ -196,8 +257,8 @@ func TestOrbsVotingContract_processVote_processVoteMachine_CalulateStakes_Delega h.setupEthereumValidatorsBeforeProcess(m) mockGuardiansInEthereum(m, h.electionBlock, h.guardians) h.setupEthereumGuardiansDataBeforeProcess(m) - mockStakeInEthereum(m, h.electionBlock, realD2.address, realD2.stake) - mockStakeInEthereum(m, h.electionBlock, realD3.address, realD3.stake) + mockStakedAndLockedInEthereum(m, h.electionBlock, realD2.address, realD2.stake, realD2.lockedStake) + mockStakedAndLockedInEthereum(m, h.electionBlock, realD3.address, realD3.stake, realD3.lockedStake) // call expectedNumOfStateTransitions := len(h.guardians) + len(h.delegators) + len(h.validators) + 3 @@ -261,9 +322,9 @@ func TestOrbsVotingContract_processVote_collectValidatorDataFromEthereum(t *test // prepare h.setupOrbsStateBeforeProcessMachine() mockValidatorOrbsAddressInEthereum(m, h.electionBlock, v1.address, v1.orbsAddress) - mockStakeInEthereum(m, h.electionBlock, v1.address, 250) + mockStakedAndLockedInEthereum(m, h.electionBlock, v1.address, 250, 250) mockValidatorOrbsAddressInEthereum(m, h.electionBlock, v2.address, v2.orbsAddress) - mockStakeInEthereum(m, h.electionBlock, v2.address, 450) + mockStakedAndLockedInEthereum(m, h.electionBlock, v2.address, 450, 450) _setVotingProcessItem(0) // call @@ -275,9 +336,9 @@ func TestOrbsVotingContract_processVote_collectValidatorDataFromEthereum(t *test // assert m.VerifyMocks() require.EqualValues(t, i, _getVotingProcessItem()) - require.EqualValues(t, 250, state.ReadUint64(_formatValidatorStakeKey(v1.address[:]))) + require.EqualValues(t, 500, state.ReadUint64(_formatValidatorStakeKey(v1.address[:]))) require.EqualValues(t, v1.orbsAddress[:], state.ReadBytes(_formatValidatorOrbsAddressKey(v1.address[:]))) - require.EqualValues(t, 450, state.ReadUint64(_formatValidatorStakeKey(v2.address[:]))) + require.EqualValues(t, 900, state.ReadUint64(_formatValidatorStakeKey(v2.address[:]))) require.EqualValues(t, v2.orbsAddress[:], state.ReadBytes(_formatValidatorOrbsAddressKey(v2.address[:]))) }) } @@ -361,6 +422,7 @@ func TestOrbsVotingContract_processVote_collectGuardiansStakeFromEthereum(t *tes var v1 = h.addValidator() var g1, g2 = h.addGuardian(400), h.addGuardian(600) + g1.lockedStake = 500 g1.vote(aRecentVoteBlock, v1) g2.vote(aRecentVoteBlock, v1) @@ -382,7 +444,7 @@ func TestOrbsVotingContract_processVote_collectGuardiansStakeFromEthereum(t *tes // assert m.VerifyMocks() require.EqualValues(t, i, _getVotingProcessItem()) - require.EqualValues(t, 400, state.ReadUint64(_formatGuardianStakeKey(g1.address[:]))) + require.EqualValues(t, 900, state.ReadUint64(_formatGuardianStakeKey(g1.address[:]))) require.ElementsMatch(t, [][20]byte{v1.address}, _getCandidates(g1.address[:])) require.EqualValues(t, 600, state.ReadUint64(_formatGuardianStakeKey(g2.address[:]))) require.ElementsMatch(t, [][20]byte{v1.address}, _getCandidates(g2.address[:])) @@ -435,7 +497,7 @@ func TestOrbsVotingContract_processVote_collectOneDelegatorStakeFromEthereum_NoS // prepare h.setupOrbsStateBeforeProcessMachine() - mockStakeInEthereum(m, h.electionBlock, [20]byte{}, 0) + mockStakedAndLockedInEthereum(m, h.electionBlock, [20]byte{}, 0, 0) // call _collectOneDelegatorStakeFromEthereum(0) From ad96a16bf88d4df0a1d9e8e13a779bdaa24896d2 Mon Sep 17 00:00:00 2001 From: Noam Berg Date: Tue, 31 Mar 2020 18:40:14 +0300 Subject: [PATCH 2/2] new ethereum lock contract and address --- .../native/repository/_Elections/ethereum_binding.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/services/processor/native/repository/_Elections/ethereum_binding.go b/services/processor/native/repository/_Elections/ethereum_binding.go index 162736c25..35fc1f584 100644 --- a/services/processor/native/repository/_Elections/ethereum_binding.go +++ b/services/processor/native/repository/_Elections/ethereum_binding.go @@ -10,7 +10,7 @@ package elections_systemcontract * Connections to Ethereum contracts */ var ETHEREUM_TOKEN_ADDR = "0xff56Cc6b1E6dEd347aA0B7676C85AB0B3D08B0FA" -var ETHEREUM_STAKING_ADDR = "0xff56Cc6b1E6dEd347aA0B7676C85AB0B3D08B0FA" // TODO LOCKING replace with actual contract address +var ETHEREUM_STAKING_ADDR = "0x0cD370eDcBbD783815a7f45beeA559b47D39de15" var ETHEREUM_VOTING_ADDR = "0x30f855afb78758Aa4C2dc706fb0fA3A98c865d2d" var ETHEREUM_VALIDATORS_ADDR = "0x240fAa45557c61B6959162660E324Bb90984F00f" var ETHEREUM_VALIDATORS_REGISTRY_ADDR = "0x56A6895FD37f358c17cbb3F14A864ea5Fe871F0a" @@ -29,7 +29,7 @@ func getStakingEthereumContractAddress() string { } func getStakingAbi() string { - return `[{"anonymous":false,"inputs":[{"indexed":true,"name":"stakeOwner","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"totalStakedAmount","type":"uint256"}],"name":"Staked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"stakeOwner","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"totalStakedAmount","type":"uint256"}],"name":"Unstaked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"stakeOwner","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"totalStakedAmount","type":"uint256"}],"name":"Withdrew","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"stakeOwner","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"totalStakedAmount","type":"uint256"}],"name":"Restaked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"stakeOwner","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"totalStakedAmount","type":"uint256"}],"name":"MigratedStake","type":"event"},{"constant":false,"inputs":[{"name":"_amount","type":"uint256"}],"name":"stake","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_amount","type":"uint256"}],"name":"unstake","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"withdraw","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"restake","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_totalAmount","type":"uint256"},{"name":"_stakeOwners","type":"address[]"},{"name":"_amounts","type":"uint256[]"}],"name":"distributeRewards","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_stakeOwner","type":"address"}],"name":"getStakeBalanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getTotalStakedTokens","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_stakeOwner","type":"address"}],"name":"getUnstakeStatus","outputs":[{"name":"cooldownAmount","type":"uint256"},{"name":"cooldownEndTime","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_newStakingContract","type":"address"},{"name":"_amount","type":"uint256"}],"name":"migrateStakedTokens","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"}]` + return `[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"stakeOwner","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalStakedAmount","type":"uint256"}],"name":"MigratedStake","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"stakeOwner","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalStakedAmount","type":"uint256"}],"name":"Restaked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"stakeOwner","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalStakedAmount","type":"uint256"}],"name":"Staked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"stakeOwner","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalStakedAmount","type":"uint256"}],"name":"Unstaked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"stakeOwner","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalStakedAmount","type":"uint256"}],"name":"Withdrew","type":"event"},{"constant":false,"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"stake","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"unstake","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"withdraw","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"restake","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"_totalAmount","type":"uint256"},{"internalType":"address[]","name":"_stakeOwners","type":"address[]"},{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"}],"name":"distributeRewards","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_stakeOwner","type":"address"}],"name":"getStakeBalanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getTotalStakedTokens","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_stakeOwner","type":"address"}],"name":"getUnstakeStatus","outputs":[{"internalType":"uint256","name":"cooldownAmount","type":"uint256"},{"internalType":"uint256","name":"cooldownEndTime","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"contract IMigratableStakingContract","name":"_newStakingContract","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"migrateStakedTokens","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"}]` } func getGuardiansEthereumContractAddress() string {