Skip to content

Commit

Permalink
[RFC-201/205] Staking and validator storage rework (#1442)
Browse files Browse the repository at this point in the history
* Use rework branch on core-contracts

* EVM-578: Deploy new contracts for staking and supernets (#1368)

* Deploy root contracts

* New child contracts deployment

* Lint fix

* nil reference exception fix

* Comments fix

* Rebase fix

* [RFC-201/205]: EVM-596-Change whitelist and register commands (#1404)

* Change whitelist and register commands

* Build fix

* Lint fix

* Include submodule fix

* Remove leftover const

* Minor change

* Minor updates

* Check error before checking doesMatch flag

* Add private key flag to whitelist command

* two new GetXYZFromSecret methods

* Change whitelist command for secrets

* Lint fix

---------

Co-authored-by: Stefan Negovanović <stefan@ethernal.tech>
Co-authored-by: Igor Crevar <crewce@gmail.com>

* [RFC-201/205]: EVM-603-Register supernet and child chain (#1406)

* Register child chain to StakeManager

* Lint fix

* Small fix

* Comments fix

* [RFC-201/205]: EVM-606-Change stake command (#1408)

* Change stake command

* Build fix

* Bring commands back to polybft command

* Validate jsonRPC address

* Comments fix

* Build fix

* Lint fix

* [RFC-201/205]: EVM-608-Supernet command (#1409)

* Supernet command

* Use GetECDSAKey in whitelist command

* Validate jsonRPC address

* Comments fix

* Comments fix

* Rebase fix

* [RFC201/205]: EVM-613-Change validator info command (#1421)

* Change validator info command

* Lint fix

* [RFC-201/205]: EVM-582-Validate validator set delta (#1423)

* Validate validator set delta

* Lint fix

* Remove comment

* Add test

* [RFC-201/205]: EVM-580-Update validator set in stake manager (#1431)

* Initial changes

* Lint fix

* Comments fix

* Comments fix

* Remove comment

* Comments fix

* Improve sorted map

* Comments fix

* Lint fix

* Add comments in code

* Comments fix

* New UT

* Lint fix

* Call stakeManager in consensus runtime

* Testing deterministic behavior of sort by stake

* simple changes

* even simplier things

* different stakeMap and some refactoring

* lower number of execution times for test

* fix

---------

Co-authored-by: Igor Crevar <crewce@gmail.com>

* [RFC-201/205]: EVM-619-Commit-epoch-on-new-ValidatorSet-contract (#1436)

* Initial changes

* Change withdraw command

* Unstake command change

* Remove ChildValidatorSet

* Deploy MockRewardContract

* Deploy contract fix

* Lint fix

* Fix sc_integration_test

* Separate unstake and withdraw

* Comments fix

* [RFC-201/205]: EVM-622-Save full validator set in db (#1445)

* Save full validator set in db

* Lint fix

* Fix

* Test fix

* validatorStakeMap refactor

* lint fix

---------

Co-authored-by: Igor Crevar <crewce@gmail.com>

* [RFC-201/205]: EVM-579-Change deployment steps in e2e tests (#1446)

* Add whitelist and register validator steps to e2e tests

* Initial staking on genesis

* Finalize genesis set on supernet manager

* Parallelize register and stake commands

* Lint fix

* Small optimization

* Comments fix

* Return negative case MakeKOSKSignature test

* Lint fix

* [RFC-201/205]: Reward token configuration (#1453)

* New init of contracts

* Reward token configuration

* Rebase fix

* Lint fix

* Validate wallet amount in genesis

* Comments fix

* Comments fix

* Comments fix

* Return chainId in KOSK signature

* Fix KOSK signature

* [RFC-201/205] E2E test fixing (#1452)

* WithoutBridge

* fix fund command test

* Remove WithBridge invocation

* Rename error message

* Rename to initializeNew (unblock whitelist)

* kosk refactor

* Kosk key fix

* Lint fix

* Kosk signature print

* Remove chainID from register command

* Remove leftovers and lint fixes

* Remove chain-id flag from register validator command

* Remove feat-polybft-release for core-contracts submodule

* Remove delegation e2e test

* GetValidatorInfo refactor

* Remove comments

* Latest SC spec

* Leftover and comment

* Fix Test_MakeKOSKSignature

* Fix GetValidatorInfo, partially fix stake function

* RewardPool updates

* Withdraw child and withdraw root functions, obsolete e2e test with delegate

* Increase timeout to 1.5h

* Lint fix

* Register and white list validators

* Fix typo

* ChangeVotingPower test fix

* Lint fix

* Fund per validator

* Unstake test fix

* amount should be big.Int

* Update SCs and lint fix

* Fix TestE2E_Consensus_MintableERC20NativeToken

* Fix TestE2E_Consensus_Validator_Unstake

* Unstake test fix

* Fix RegisterValidator test

* Lint fix

* ChangeVotingPower test modification

* TestIntegration_CommitEpoch fix

* Fix TestE2E_Bridge_ChangeVotingPower

* Minor fixes

* Fix TestE2E_Bridge_ChangeVotingPower (part 2)

* Update smart contracts

* Remove commented code

* RFC-201-205 Stake manager db fix (#1457)

* stake manager db fix

* bls key

* Fix with Data field error on logs

* Fix timeout

* Fix test timeout

* Copy data array

* Remove log copying from bindings generator

* Wait for epoch ending block in ChangeVotingPower e2e test

* Persist initial validator set as epoch id 0

---------

Co-authored-by: Goran Rojovic <goran.rojovic@ethernal.tech>
Co-authored-by: Stefan Negovanović <stefan@ethernal.tech>

* Update README

---------

Co-authored-by: Stefan Negovanović <stefan@ethernal.tech>
Co-authored-by: Goran Rojovic <goran.rojovic@ethernal.tech>

* Update stake in genesis based on finalized stake on StakeManager

* Lint fix

* Remove init function from consensus_test.go

* Small code cleanup

* Reward config fix

* E2E test for custom reward token

* Lint fix

* New stake manager UTs

---------

Co-authored-by: Stefan Negovanović <stefan@ethernal.tech>
Co-authored-by: Igor Crevar <crewce@gmail.com>
Co-authored-by: Stefan Negovanović <93934272+Stefan-Ethernal@users.noreply.github.com>
  • Loading branch information
4 people authored May 3, 2023
1 parent bb3dd32 commit fe843f6
Show file tree
Hide file tree
Showing 97 changed files with 5,438 additions and 2,554 deletions.
2 changes: 0 additions & 2 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,3 @@
[submodule "core-contracts"]
path = core-contracts
url = https://github.com/0xPolygon/core-contracts
shallow = true
branch = feat-polybft-release
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ test-e2e-polybft:
# We can not build with race because of a bug in boltdb dependency
go build -o artifacts/polygon-edge .
env EDGE_BINARY=${PWD}/artifacts/polygon-edge E2E_TESTS=true E2E_LOGS=true \
go test -v -timeout=45m ./e2e-polybft/e2e/...
go test -v -timeout=1h30m ./e2e-polybft/e2e/...

.PHONY: test-property-polybft
test-property-polybft:
Expand Down
48 changes: 3 additions & 45 deletions command/bridge/deposit/erc20/deposit_erc20.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,8 @@ func runCommand(cmd *cobra.Command, _ []string) {

if dp.testMode {
// mint tokens to depositor, so he is able to send them
mintTxn, err := createMintTxn(types.Address(depositorAddr), types.Address(depositorAddr), aggregateAmount)
mintTxn, err := helper.CreateMintTxn(types.Address(depositorAddr),
types.StringToAddress(dp.TokenAddr), aggregateAmount)
if err != nil {
outputter.SetError(fmt.Errorf("mint transaction creation failed: %w", err))

Expand All @@ -165,7 +166,7 @@ func runCommand(cmd *cobra.Command, _ []string) {
}

// approve root erc20 predicate
approveTxn, err := createApproveERC20PredicateTxn(aggregateAmount,
approveTxn, err := helper.CreateApproveERC20Txn(aggregateAmount,
types.StringToAddress(dp.PredicateAddr),
types.StringToAddress(dp.TokenAddr))
if err != nil {
Expand Down Expand Up @@ -253,49 +254,6 @@ func createDepositTxn(sender, receiver types.Address, amount *big.Int) (*ethgo.T
}, nil
}

// createMintTxn encodes parameters for mint function on rootchain token contract
func createMintTxn(sender, receiver types.Address, amount *big.Int) (*ethgo.Transaction, error) {
mintFn := &contractsapi.MintRootERC20Fn{
To: receiver,
Amount: amount,
}

input, err := mintFn.EncodeAbi()
if err != nil {
return nil, fmt.Errorf("failed to encode provided parameters: %w", err)
}

addr := ethgo.Address(types.StringToAddress(dp.TokenAddr))

return &ethgo.Transaction{
From: ethgo.Address(sender),
To: &addr,
Input: input,
}, nil
}

// createApproveERC20PredicateTxn sends approve transaction
// to ERC20 token for ERC20 predicate so that it is able to spend given tokens
func createApproveERC20PredicateTxn(amount *big.Int,
rootERC20Predicate, rootERC20Token types.Address) (*ethgo.Transaction, error) {
approveFnParams := &contractsapi.ApproveRootERC20Fn{
Spender: rootERC20Predicate,
Amount: amount,
}

input, err := approveFnParams.EncodeAbi()
if err != nil {
return nil, fmt.Errorf("failed to encode parameters for RootERC20.approve. error: %w", err)
}

addr := ethgo.Address(rootERC20Token)

return &ethgo.Transaction{
To: &addr,
Input: input,
}, nil
}

type depositERC20Result struct {
Sender string `json:"sender"`
Receivers []string `json:"receivers"`
Expand Down
16 changes: 15 additions & 1 deletion command/genesis/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ func setFlags(cmd *cobra.Command) {
&params.validators,
validatorsFlag,
[]string{},
"validators defined by user (format: <P2P multi address>:<ECDSA address>:<public BLS key>:<BLS signature>)",
"validators defined by user (format: <P2P multi address>:<ECDSA address>:<public BLS key>)",
)

cmd.Flags().StringArrayVar(
Expand Down Expand Up @@ -232,6 +232,20 @@ func setFlags(cmd *cobra.Command) {
"",
"configuration of native token in format <name:symbol:decimals count>",
)

cmd.Flags().StringVar(
&params.rewardTokenCode,
rewardTokenCodeFlag,
"",
"hex encoded reward token byte code",
)

cmd.Flags().StringVar(
&params.rewardWallet,
rewardWalletFlag,
"",
"configuration of reward wallet in format <address:amount>",
)
}

// Access Control Lists
Expand Down
34 changes: 34 additions & 0 deletions command/genesis/params.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"errors"
"fmt"
"math"
"math/big"
"os"
"strconv"
"strings"
Expand Down Expand Up @@ -37,6 +38,8 @@ const (
maxValidatorCount = "max-validator-count"
mintableTokenFlag = "mintable-native-token"
nativeTokenConfigFlag = "native-token-config"
rewardTokenCodeFlag = "reward-token-code"
rewardWalletFlag = "reward-wallet"

defaultNativeTokenName = "Polygon"
defaultNativeTokenSymbol = "MATIC"
Expand All @@ -59,6 +62,7 @@ var (
errInvalidEpochSize = errors.New("epoch size must be greater than 1")
errInvalidTokenParams = errors.New("native token params were not submitted in proper" +
" format <name:symbol:decimals count>")
errRewardWalletAmountZero = errors.New("reward wallet amount can not be zero or negative")
)

type genesisParams struct {
Expand Down Expand Up @@ -121,6 +125,10 @@ type genesisParams struct {
mintableNativeToken bool
nativeTokenConfigRaw string
nativeTokenConfig *polybft.TokenConfig

// rewards
rewardTokenCode string
rewardWallet string
}

func (p *genesisParams) validateFlags() error {
Expand All @@ -140,6 +148,10 @@ func (p *genesisParams) validateFlags() error {
if err := p.extractNativeTokenMetadata(); err != nil {
return err
}

if err := p.validateRewardWallet(); err != nil {
return err
}
}

// Check if the genesis file already exists
Expand Down Expand Up @@ -440,6 +452,28 @@ func (p *genesisParams) predeployStakingSC() (*chain.GenesisAccount, error) {
return stakingAccount, nil
}

// validateRewardWallet validates reward wallet flag
func (p *genesisParams) validateRewardWallet() error {
if p.rewardWallet == "" {
return errors.New("reward wallet address must be defined")
}

if p.rewardWallet == types.AddressToString(types.ZeroAddress) {
return errors.New("reward wallet address must not be zero address")
}

premineInfo, err := parsePremineInfo(p.rewardWallet)
if err != nil {
return err
}

if premineInfo.amount.Cmp(big.NewInt(0)) < 1 {
return errRewardWalletAmountZero
}

return nil
}

// extractNativeTokenMetadata parses provided native token metadata (such as name, symbol and decimals count)
func (p *genesisParams) extractNativeTokenMetadata() error {
if p.nativeTokenConfigRaw == "" {
Expand Down
85 changes: 60 additions & 25 deletions command/genesis/polybft_params.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package genesis

import (
"encoding/hex"
"errors"
"fmt"
"math/big"
Expand Down Expand Up @@ -58,7 +59,6 @@ const (

ecdsaAddressLength = 40
blsKeyLength = 256
blsSignatureLength = 128
)

var (
Expand All @@ -79,6 +79,30 @@ func (p *genesisParams) generatePolyBftChainConfig(o command.OutputFormatter) er
premineBalances[premineInfo.address] = premineInfo
}

walletPremineInfo, err := parsePremineInfo(p.rewardWallet)
if err != nil {
return fmt.Errorf("invalid reward wallet configuration provided '%s' : %w", p.rewardWallet, err)
}

var (
rewardTokenByteCode []byte
rewardTokenAddr = contracts.NativeERC20TokenContract
)

if p.rewardTokenCode == "" {
// native token is used as a reward token, and reward wallet is not a zero address
// so we need to add that address to premine map
premineBalances[walletPremineInfo.address] = walletPremineInfo
} else {
bytes, err := hex.DecodeString(p.rewardTokenCode)
if err != nil {
return fmt.Errorf("could not decode reward token byte code '%s' : %w", p.rewardTokenCode, err)
}

rewardTokenByteCode = bytes
rewardTokenAddr = contracts.RewardTokenContract
}

initialValidators, err := p.getValidatorAccounts(premineBalances)
if err != nil {
return fmt.Errorf("failed to retrieve genesis validators: %w", err)
Expand Down Expand Up @@ -109,6 +133,12 @@ func (p *genesisParams) generatePolyBftChainConfig(o command.OutputFormatter) er
InitialTrieRoot: types.StringToHash(p.initialStateRoot),
MintableNativeToken: p.mintableNativeToken,
NativeTokenConfig: p.nativeTokenConfig,
MaxValidatorSetSize: p.maxNumValidators,
RewardConfig: &polybft.RewardsConfig{
TokenAddress: rewardTokenAddr,
WalletAddress: walletPremineInfo.address,
WalletAmount: walletPremineInfo.amount,
},
}

// Disable london hardfork if burn contract address is not provided
Expand All @@ -120,8 +150,7 @@ func (p *genesisParams) generatePolyBftChainConfig(o command.OutputFormatter) er
chainConfig := &chain.Chain{
Name: p.name,
Params: &chain.Params{
ChainID: int64(p.chainID),
Forks: enabledForks,
Forks: enabledForks,
Engine: map[string]interface{}{
string(server.PolyBFTConsensus): polyBftConfig,
},
Expand All @@ -137,7 +166,7 @@ func (p *genesisParams) generatePolyBftChainConfig(o command.OutputFormatter) er
}

// deploy genesis contracts
allocs, err := p.deployContracts(totalStake)
allocs, err := p.deployContracts(totalStake, rewardTokenByteCode, polyBftConfig)
if err != nil {
return err
}
Expand Down Expand Up @@ -270,18 +299,15 @@ func (p *genesisParams) generatePolyBftChainConfig(o command.OutputFormatter) er
return helper.WriteGenesisConfigToDisk(chainConfig, params.genesisPath)
}

func (p *genesisParams) deployContracts(totalStake *big.Int) (map[types.Address]*chain.GenesisAccount, error) {
func (p *genesisParams) deployContracts(totalStake *big.Int,
rewardTokenByteCode []byte,
polybftConfig *polybft.PolyBFTConfig) (map[types.Address]*chain.GenesisAccount, error) {
type contractInfo struct {
artifact *artifact.Artifact
address types.Address
}

genesisContracts := []*contractInfo{
{
// ChildValidatorSet contract
artifact: contractsapi.ChildValidatorSet,
address: contracts.ValidatorSetContract,
},
{
// State receiver contract
artifact: contractsapi.StateReceiver,
Expand Down Expand Up @@ -332,6 +358,14 @@ func (p *genesisParams) deployContracts(totalStake *big.Int) (map[types.Address]
artifact: contractsapi.L2StateSender,
address: contracts.L2StateSenderContract,
},
{
artifact: contractsapi.ValidatorSet,
address: contracts.ValidatorSetContract,
},
{
artifact: contractsapi.RewardPool,
address: contracts.RewardPoolContract,
},
}

if !params.mintableNativeToken {
Expand All @@ -342,7 +376,7 @@ func (p *genesisParams) deployContracts(totalStake *big.Int) (map[types.Address]
&contractInfo{artifact: contractsapi.NativeERC20Mintable, address: contracts.NativeERC20TokenContract})
}

allocations := make(map[types.Address]*chain.GenesisAccount, len(genesisContracts))
allocations := make(map[types.Address]*chain.GenesisAccount, len(genesisContracts)+1)

for _, contract := range genesisContracts {
allocations[contract.address] = &chain.GenesisAccount{
Expand All @@ -351,8 +385,14 @@ func (p *genesisParams) deployContracts(totalStake *big.Int) (map[types.Address]
}
}

// ChildValidatorSet must have funds pre-allocated, because of withdrawal workflow
allocations[contracts.ValidatorSetContract].Balance = totalStake
if rewardTokenByteCode != nil {
// if reward token is provided in genesis then, add it to allocations
// to RewardTokenContract address and update polybftConfig
allocations[contracts.RewardTokenContract] = &chain.GenesisAccount{
Balance: big.NewInt(0),
Code: rewardTokenByteCode,
}
}

return allocations, nil
}
Expand Down Expand Up @@ -388,9 +428,9 @@ func (p *genesisParams) getValidatorAccounts(
validators := make([]*polybft.Validator, len(p.validators))
for i, validator := range p.validators {
parts := strings.Split(validator, ":")
if len(parts) != 4 {
if len(parts) != 3 {
return nil, fmt.Errorf("expected 4 parts provided in the following format "+
"<P2P multi address:ECDSA address:public BLS key:BLS signature>, but got %d part(s)",
"<P2P multi address:ECDSA address:public BLS key>, but got %d part(s)",
len(parts))
}

Expand All @@ -408,18 +448,13 @@ func (p *genesisParams) getValidatorAccounts(
return nil, fmt.Errorf("invalid BLS key: %s", parts[2])
}

if len(parts[3]) != blsSignatureLength {
return nil, fmt.Errorf("invalid BLS signature: %s", parts[3])
}

addr := types.StringToAddress(trimmedAddress)
validators[i] = &polybft.Validator{
MultiAddr: parts[0],
Address: addr,
BlsKey: trimmedBLSKey,
BlsSignature: parts[3],
Balance: getPremineAmount(addr, premineBalances, command.DefaultPremineBalance),
Stake: getPremineAmount(addr, stakeMap, command.DefaultStake),
MultiAddr: parts[0],
Address: addr,
BlsKey: trimmedBLSKey,
Balance: getPremineAmount(addr, premineBalances, command.DefaultPremineBalance),
Stake: getPremineAmount(addr, stakeMap, command.DefaultStake),
}
}

Expand Down
Loading

0 comments on commit fe843f6

Please sign in to comment.