Skip to content

Commit

Permalink
Integrate with CheckpointManager.sol (#952)
Browse files Browse the repository at this point in the history
* Integrate with CheckpointManager.sol

* Hex encode ECDSA private key

* Skip failing tests for checkpoint manager

* Fix submit function signature

* Remove logs and set From field to submit checkpoint transaction

* Pass signer key to rootchain.SendTxn function

* Pull console precompile Geth docker image

* Populate voting power on checkpoint manager initialization

* Hash change

* Minor fixes (ordering of abi ancoded parameters)

* Populate voting power on genesis block

* Fix balance scaling

* Fix TestCheckpointManager_isCheckpointBlock

* Remove sorting by addresses on validators snapshot calculation

* Sort validators by addresses on genesis header population

* Sort validators by addresses on rootchain initialization

* Logging...

* Update core-contracts

* Fix checkpoint manager unit tests

* Change comment + unit tests for helper functions

* Revert usage of Geth console fork

* Include Geth console fork again

* Rename latestCheckpointBlockNumber to currentCheckpointBlockNumber

* Remove logs and revert to use official Geth image for rootchain server

* Code cleanup

* Add meaningful logs to the checkpoint manager

* not buildable

* full functional bn254

* Use proper domain when initializing CheckpointManager contract

* Fix go mod

* Revert helper bash scripts

* Fix e2e tests

* Address Igor's comment

* Provide `epochSize` to the `ChildValidatorSet` (#983)

* Provide epochSize to the ChildValidatorSet

* Rename newBls map key

* Rename parameters

* Point to our branch in core-contracts

Co-authored-by: Goran Rojovic <goran.rojovic@ethernal.tech>

Co-authored-by: Stefan Negovanović <stefan@ethernal.tech>
Co-authored-by: Nemanja0x <nemanja@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
5 people committed Nov 30, 2022
1 parent e96eeda commit a219437
Show file tree
Hide file tree
Showing 24 changed files with 456 additions and 247 deletions.
2 changes: 1 addition & 1 deletion Makefile
Expand Up @@ -50,7 +50,7 @@ test-e2e:
go build -race -o artifacts/polygon-edge .
env EDGE_BINARY=${PWD}/artifacts/polygon-edge go test -v -timeout=30m ./e2e/...

.PHONY: test-e2ev3
.PHONY: test-e2e-polybft
test-e2e-polybft:
# We can not build with race because of a bug in boltdb dependency
go build -o artifacts/polygon-edge .
Expand Down
19 changes: 19 additions & 0 deletions chain/chain.go
Expand Up @@ -20,6 +20,10 @@ var (
GenesisDifficulty = big.NewInt(131072)
)

const (
weiScalingFactor = int64(1e18) // 10^18
)

// Chain is the blockchain chain configuration
type Chain struct {
Name string `json:"name"`
Expand Down Expand Up @@ -361,3 +365,18 @@ func importChain(content []byte) (*Chain, error) {

return chain, nil
}

// GetGenesisAccountBalance returns balance for genesis account based on its address (expressed in weis).
// If not found in provided allocations map, 0 is returned.
func GetGenesisAccountBalance(address types.Address, allocations map[types.Address]*GenesisAccount) (*big.Int, error) {
if genesisAcc, ok := allocations[address]; ok {
return genesisAcc.Balance, nil
}

return nil, fmt.Errorf("genesis account %s is not found among genesis allocations", address)
}

// ConvertWeiToTokensAmount converts provided wei amount to tokens amount
func ConvertWeiToTokensAmount(weiAmount *big.Int) *big.Int {
return new(big.Int).Div(weiAmount, big.NewInt(weiScalingFactor))
}
53 changes: 53 additions & 0 deletions chain/chain_test.go
Expand Up @@ -2,11 +2,13 @@ package chain

import (
"encoding/json"
"fmt"
"math/big"
"reflect"
"testing"

"github.com/0xPolygon/polygon-edge/types"
"github.com/stretchr/testify/require"
)

var emptyAddr types.Address
Expand Down Expand Up @@ -150,3 +152,54 @@ func TestGenesisX(t *testing.T) {
})
}
}

func TestGetGenesisAccountBalance(t *testing.T) {
t.Parallel()

testAddr := types.Address{0x2}
cases := []struct {
name string
address types.Address
allocs map[types.Address]*GenesisAccount
expectedBalance *big.Int
shouldFail bool
}{
{
name: "Query existing account",
address: testAddr,
allocs: map[types.Address]*GenesisAccount{
testAddr: {Balance: big.NewInt(50)},
},
expectedBalance: big.NewInt(50),
shouldFail: false,
},
{
name: "Query non-existing account",
address: testAddr,
allocs: nil,
expectedBalance: nil,
shouldFail: true,
},
}

for _, c := range cases {
c := c
t.Run(c.name, func(t *testing.T) {
t.Parallel()

actualBalance, err := GetGenesisAccountBalance(c.address, c.allocs)
if c.shouldFail {
require.Equal(t, err.Error(), fmt.Errorf("genesis account %s is not found among genesis allocations", c.address).Error())
} else {
require.NoError(t, err)
}
require.Equal(t, c.expectedBalance, actualBalance)
})
}
}

func TestConvertWeiToTokensAmount(t *testing.T) {
t.Parallel()

require.Equal(t, big.NewInt(30), ConvertWeiToTokensAmount(new(big.Int).Mul(big.NewInt(30), big.NewInt(1e18))))
}
39 changes: 11 additions & 28 deletions command/genesis/polybft_params.go
@@ -1,10 +1,12 @@
package genesis

import (
"bytes"
"encoding/hex"
"fmt"
"math/big"
"path"
"sort"
"strings"
"time"

Expand Down Expand Up @@ -40,8 +42,6 @@ const (
defaultBridge = false

bootnodePortStart = 30301

WeiScalingFactor = 1_000_000_000_000_000_000 // 10^18
)

func (p *genesisParams) generatePolyBFTConfig() (*chain.Chain, error) {
Expand Down Expand Up @@ -160,7 +160,7 @@ func (p *genesisParams) getGenesisValidators(validators []GenesisTarget,

addr := types.StringToAddress(parts[0])

balance, err := getBalanceInWei(addr, allocs)
balance, err := chain.GetGenesisAccountBalance(addr, allocs)
if err != nil {
return nil, err
}
Expand All @@ -176,7 +176,7 @@ func (p *genesisParams) getGenesisValidators(validators []GenesisTarget,
pubKeyMarshalled := validator.Account.Bls.PublicKey().Marshal()
addr := types.Address(validator.Account.Ecdsa.Address())

balance, err := getBalanceInWei(addr, allocs)
balance, err := chain.GetGenesisAccountBalance(addr, allocs)
if err != nil {
return nil, err
}
Expand All @@ -192,23 +192,6 @@ func (p *genesisParams) getGenesisValidators(validators []GenesisTarget,
return result, nil
}

// getBalanceInWei returns balance for genesis account based on its address.
// If not found in provided allocations map, 1M native tokens is returned.
func getBalanceInWei(address types.Address, allocations map[types.Address]*chain.GenesisAccount) (*big.Int, error) {
if genesisAcc, ok := allocations[address]; ok {
return genesisAcc.Balance, nil
}

val := command.DefaultPremineBalance

amount, err := types.ParseUint256orHex(&val)
if err != nil {
return nil, fmt.Errorf("failed to parse amount %s: %w", val, err)
}

return amount, nil
}

func (p *genesisParams) generatePolyBftGenesis() error {
config, err := params.generatePolyBFTConfig()
if err != nil {
Expand Down Expand Up @@ -288,16 +271,16 @@ func generateExtraDataPolyBft(validators []*polybft.Validator, publicKeys []*bls
delta.Added[i] = &polybft.ValidatorMetadata{
Address: validator.Address,
BlsKey: publicKeys[i],
VotingPower: convertWeiToTokensAmount(validator.Balance).Uint64(),
VotingPower: chain.ConvertWeiToTokensAmount(validator.Balance).Uint64(),
}
}

extra := polybft.Extra{Validators: delta}
// Order validators based on its addresses
sort.Slice(delta.Added, func(i, j int) bool {
return bytes.Compare(delta.Added[i].Address[:], delta.Added[j].Address[:]) < 0
})

return append(make([]byte, polybft.ExtraVanity), extra.MarshalRLPTo(nil)...), nil
}
extra := polybft.Extra{Validators: delta, Checkpoint: &polybft.CheckpointData{}}

// convertWeiToTokensAmount converts provided wei balance to tokens amount
func convertWeiToTokensAmount(weiBalance *big.Int) *big.Int {
return weiBalance.Div(weiBalance, big.NewInt(WeiScalingFactor))
return append(make([]byte, polybft.ExtraVanity), extra.MarshalRLPTo(nil)...), nil
}
4 changes: 2 additions & 2 deletions command/polybftsecrets/params.go
Expand Up @@ -152,11 +152,11 @@ func (ip *initParams) initKeys(secretsManager secrets.SecretsManager) error {

if ip.generatesAccount {
if secretsManager.HasSecret(secrets.ValidatorKey) {
return fmt.Errorf(`secrets "%s" has been already initialized`, secrets.ValidatorKey)
return fmt.Errorf("secrets '%s' has been already initialized", secrets.ValidatorKey)
}

if secretsManager.HasSecret(secrets.ValidatorBLSKey) {
return fmt.Errorf(`secrets "%s" has been already initialized`, secrets.ValidatorBLSKey)
return fmt.Errorf("secrets '%s' has been already initialized", secrets.ValidatorBLSKey)
}

return wallet.GenerateAccount().Save(secretsManager)
Expand Down
4 changes: 2 additions & 2 deletions command/rootchain/emit/emit.go
Expand Up @@ -76,7 +76,7 @@ func runCommand(cmd *cobra.Command, _ []string) {
return
}

pendingNonce, err := helper.GetPendingNonce(helper.GetDefAccount())
pendingNonce, err := helper.GetPendingNonce(helper.GetRootchainAdminAddr())
if err != nil {
outputter.SetError(fmt.Errorf("could not get pending nonce: %w", err))

Expand All @@ -100,7 +100,7 @@ func runCommand(cmd *cobra.Command, _ []string) {
return fmt.Errorf("failed to create tx input: %w", err)
}

if _, err = helper.SendTxn(pendingNonce+walletIndex, txn); err != nil {
if _, err = helper.SendTxn(pendingNonce+walletIndex, txn, helper.GetRootchainAdminKey()); err != nil {
return fmt.Errorf("sending transaction to wallet: %s with amount: %s, failed with error: %w", wallet, amount, err)
}

Expand Down
6 changes: 2 additions & 4 deletions command/rootchain/helper/metadata.go
Expand Up @@ -15,12 +15,10 @@ var (
StateSenderAddress = types.StringToAddress("0x6FE03c2768C9d800AF3Dedf1878b5687FE120a27")
// CheckpointManagerAddress is an address of CheckpointManager.sol smart contract
CheckpointManagerAddress = types.StringToAddress("0x3d46A809D5767B81a8836f0E79145ba615A2Dd61")
// RootValidatorSetAddress is an address of RootValidatorSet.sol smart contract
RootValidatorSetAddress = types.StringToAddress("0x72E1C51FE6dABF2e3d5701170cf5aD3620E6B8ba")
// BLSAddress is an address of BLS.sol smart contract
BLSAddress = types.StringToAddress("0x436604426F31A05f905C64edc973E575BdB46471")
BLSAddress = types.StringToAddress("0x72E1C51FE6dABF2e3d5701170cf5aD3620E6B8ba")
// BN256G2Address is an address of BN256G2Address.sol smart contract
BN256G2Address = types.StringToAddress("0x947a581B2713F58A8145201DA41BCb6aAE90196B")
BN256G2Address = types.StringToAddress("0x436604426F31A05f905C64edc973E575BdB46471")

ErrRootchainNotFound = errors.New("rootchain not found")
ErrRootchainPortBind = errors.New("port 8545 is not bind with localhost")
Expand Down
16 changes: 10 additions & 6 deletions command/rootchain/helper/txn.go
Expand Up @@ -22,7 +22,7 @@ const (
var (
// use a deterministic wallet/private key so that the address of the deployed contracts
// are deterministic
defKey *wallet.Key
rootchainAdminKey *wallet.Key

jrpcClientLock sync.Mutex
jsonRPCClient *jsonrpc.Client
Expand All @@ -34,19 +34,23 @@ func init() {
panic(err)
}

defKey, err = wallet.NewWalletFromPrivKey(dec)
rootchainAdminKey, err = wallet.NewWalletFromPrivKey(dec)
if err != nil {
panic(err)
}
}

func GetDefAccount() types.Address {
return types.BytesToAddress(defKey.Address().Bytes())
func GetRootchainAdminAddr() types.Address {
return types.Address(rootchainAdminKey.Address())
}

func GetRootchainAdminKey() ethgo.Key {
return rootchainAdminKey
}

// SendTxn function sends transaction to the rootchain
// blocks until receipt hash is returned
func SendTxn(nonce uint64, txn *ethgo.Transaction) (*ethgo.Receipt, error) {
func SendTxn(nonce uint64, txn *ethgo.Transaction, key ethgo.Key) (*ethgo.Receipt, error) {
provider, err := getJSONRPCClient()
if err != nil {
return nil, err
Expand All @@ -62,7 +66,7 @@ func SendTxn(nonce uint64, txn *ethgo.Transaction) (*ethgo.Receipt, error) {
}

signer := wallet.NewEIP155Signer(chainID.Uint64())
if txn, err = signer.SignTx(txn, defKey); err != nil {
if txn, err = signer.SignTx(txn, key); err != nil {
return nil, err
}

Expand Down

0 comments on commit a219437

Please sign in to comment.