Skip to content

Commit

Permalink
Merge pull request #84 from 0glabs/staking-precompile
Browse files Browse the repository at this point in the history
feat: staking precompile
  • Loading branch information
MiniFrenchBread authored Nov 11, 2024
2 parents f2abb98 + 100bad3 commit 76eebc5
Show file tree
Hide file tree
Showing 26 changed files with 8,956 additions and 28 deletions.
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,8 @@ go.work.sum

# runtime
run

# contracts
precompiles/interfaces/build
precompiles/interfaces/node_modules
precompiles/interfaces/abis
10 changes: 9 additions & 1 deletion app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ import (
chainparams "github.com/0glabs/0g-chain/app/params"
"github.com/0glabs/0g-chain/chaincfg"
dasignersprecompile "github.com/0glabs/0g-chain/precompiles/dasigners"
stakingprecompile "github.com/0glabs/0g-chain/precompiles/staking"

"github.com/0glabs/0g-chain/x/bep3"
bep3keeper "github.com/0glabs/0g-chain/x/bep3/keeper"
Expand Down Expand Up @@ -499,11 +500,18 @@ func NewApp(
app.dasignersKeeper = dasignerskeeper.NewKeeper(keys[dasignerstypes.StoreKey], appCodec, app.stakingKeeper, govAuthAddrStr)
// precopmiles
precompiles := make(map[common.Address]vm.PrecompiledContract)
// dasigners
daSignersPrecompile, err := dasignersprecompile.NewDASignersPrecompile(app.dasignersKeeper)
if err != nil {
panic("initialize precompile failed")
panic(fmt.Sprintf("initialize dasigners precompile failed: %v", err))
}
precompiles[daSignersPrecompile.Address()] = daSignersPrecompile
// staking
stakingPrecompile, err := stakingprecompile.NewStakingPrecompile(app.stakingKeeper)
if err != nil {
panic(fmt.Sprintf("initialize staking precompile failed: %v", err))
}
precompiles[stakingPrecompile.Address()] = stakingPrecompile

app.evmKeeper = evmkeeper.NewKeeper(
appCodec, keys[evmtypes.StoreKey], tkeys[evmtypes.TransientKey],
Expand Down
1 change: 1 addition & 0 deletions precompiles/common/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ package common
const (
ErrGetStateDB = "get EVM StateDB failed"
ErrInvalidNumberOfArgs = "invalid number of arguments; expected %d; got: %d"
ErrSenderNotOrigin = "msg.sender is not from tx origin"
)
18 changes: 18 additions & 0 deletions precompiles/common/utils.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package common

import (
"math/big"
"strings"

"cosmossdk.io/math"
"github.com/ethereum/go-ethereum/common"
)

func ToLowerHexWithoutPrefix(addr common.Address) string {
return strings.ToLower(addr.Hex()[2:])
}

// BigIntToLegacyDec converts a uint number (18 decimals) to math.LegacyDec (18 decimals)
func BigIntToLegacyDec(x *big.Int) math.LegacyDec {
return math.LegacyNewDecFromBigIntWithPrec(x, math.LegacyPrecision)
}
6 changes: 3 additions & 3 deletions precompiles/dasigners/dasigners.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,11 +139,11 @@ func (d *DASignersPrecompile) Run(evm *vm.EVM, contract *vm.Contract, readonly b
bz, err = d.RegisteredEpoch(ctx, evm, method, args)
// txs
case DASignersFunctionRegisterSigner:
bz, err = d.RegisterSigner(ctx, evm, stateDB, method, args)
bz, err = d.RegisterSigner(ctx, evm, stateDB, contract, method, args)
case DASignersFunctionRegisterNextEpoch:
bz, err = d.RegisterNextEpoch(ctx, evm, stateDB, method, args)
bz, err = d.RegisterNextEpoch(ctx, evm, stateDB, contract, method, args)
case DASignersFunctionUpdateSocket:
bz, err = d.UpdateSocket(ctx, evm, stateDB, method, args)
bz, err = d.UpdateSocket(ctx, evm, stateDB, contract, method, args)
}

if err != nil {
Expand Down
9 changes: 4 additions & 5 deletions precompiles/dasigners/dasigners_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"github.com/0glabs/0g-chain/x/dasigners/v1/types"
abci "github.com/cometbft/cometbft/abci/types"
"github.com/consensys/gnark-crypto/ecc/bn254"
"github.com/cosmos/cosmos-sdk/crypto/keys/ed25519"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
Expand All @@ -23,7 +24,6 @@ import (
"cosmossdk.io/math"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/evmos/ethermint/crypto/ethsecp256k1"
)

type DASignersTestSuite struct {
Expand All @@ -44,8 +44,7 @@ func (suite *DASignersTestSuite) AddDelegation(from string, to string, amount ma
suite.Require().NoError(err)
validator, found := suite.StakingKeeper.GetValidator(suite.Ctx, valAddr)
if !found {
consPriv, err := ethsecp256k1.GenerateKey()
suite.Require().NoError(err)
consPriv := ed25519.GenPrivKey()
newValidator, err := stakingtypes.NewValidator(valAddr, consPriv.PubKey(), stakingtypes.Description{})
suite.Require().NoError(err)
validator = newValidator
Expand Down Expand Up @@ -73,8 +72,8 @@ func (suite *DASignersTestSuite) SetupTest() {
suite.Assert().EqualValues(ok, true)
suite.dasigners = precompile.(*dasignersprecompile.DASignersPrecompile)

suite.signerOne = testutil.GenSigner()
suite.signerTwo = testutil.GenSigner()
suite.signerOne = suite.GenSigner()
suite.signerTwo = suite.GenSigner()
abi, err := abi.JSON(strings.NewReader(dasignersprecompile.DASignersABI))
suite.Assert().NoError(err)
suite.abi = abi
Expand Down
4 changes: 2 additions & 2 deletions precompiles/dasigners/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ func (d *DASignersPrecompile) IsSigner(ctx sdk.Context, _ *vm.EVM, method *abi.M
if len(args) != 1 {
return nil, fmt.Errorf(precopmiles_common.ErrInvalidNumberOfArgs, 1, len(args))
}
account := ToLowerHexWithoutPrefix(args[0].(common.Address))
account := precopmiles_common.ToLowerHexWithoutPrefix(args[0].(common.Address))
_, found, err := d.dasignersKeeper.GetSigner(ctx, account)
if err != nil {
return nil, err
Expand All @@ -74,7 +74,7 @@ func (d *DASignersPrecompile) RegisteredEpoch(ctx sdk.Context, _ *vm.EVM, method
if len(args) != 2 {
return nil, fmt.Errorf(precopmiles_common.ErrInvalidNumberOfArgs, 2, len(args))
}
account := ToLowerHexWithoutPrefix(args[0].(common.Address))
account := precopmiles_common.ToLowerHexWithoutPrefix(args[0].(common.Address))
epoch := args[1].(*big.Int).Uint64()
_, found, err := d.dasignersKeeper.GetRegistration(ctx, epoch, account)
if err != nil {
Expand Down
46 changes: 40 additions & 6 deletions precompiles/dasigners/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,30 @@ import (
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/evmos/ethermint/x/evm/statedb"

precopmiles_common "github.com/0glabs/0g-chain/precompiles/common"
)

func (d *DASignersPrecompile) RegisterSigner(ctx sdk.Context, evm *vm.EVM, stateDB *statedb.StateDB, method *abi.Method, args []interface{}) ([]byte, error) {
func (d *DASignersPrecompile) RegisterSigner(
ctx sdk.Context,
evm *vm.EVM,
stateDB *statedb.StateDB,
contract *vm.Contract,
method *abi.Method,
args []interface{},
) ([]byte, error) {
msg, err := NewMsgRegisterSigner(args)
if err != nil {
return nil, err
}
// validation
sender := ToLowerHexWithoutPrefix(evm.Origin)
sender := precopmiles_common.ToLowerHexWithoutPrefix(evm.Origin)
if sender != msg.Signer.Account {
return nil, fmt.Errorf(ErrInvalidSender, sender, msg.Signer.Account)
}
if contract.CallerAddress != evm.Origin {
return nil, fmt.Errorf(precopmiles_common.ErrSenderNotOrigin)
}
// execute
_, err = d.dasignersKeeper.RegisterSigner(sdk.WrapSDKContext(ctx), msg)
if err != nil {
Expand All @@ -32,11 +44,22 @@ func (d *DASignersPrecompile) RegisterSigner(ctx sdk.Context, evm *vm.EVM, state
return method.Outputs.Pack()
}

func (d *DASignersPrecompile) RegisterNextEpoch(ctx sdk.Context, evm *vm.EVM, stateDB *statedb.StateDB, method *abi.Method, args []interface{}) ([]byte, error) {
msg, err := NewMsgRegisterNextEpoch(args, ToLowerHexWithoutPrefix(evm.Origin))
func (d *DASignersPrecompile) RegisterNextEpoch(
ctx sdk.Context,
evm *vm.EVM,
stateDB *statedb.StateDB,
contract *vm.Contract,
method *abi.Method,
args []interface{},
) ([]byte, error) {
msg, err := NewMsgRegisterNextEpoch(args, precopmiles_common.ToLowerHexWithoutPrefix(evm.Origin))
if err != nil {
return nil, err
}
// validation
if contract.CallerAddress != evm.Origin {
return nil, fmt.Errorf(precopmiles_common.ErrSenderNotOrigin)
}
// execute
_, err = d.dasignersKeeper.RegisterNextEpoch(sdk.WrapSDKContext(ctx), msg)
if err != nil {
Expand All @@ -45,11 +68,22 @@ func (d *DASignersPrecompile) RegisterNextEpoch(ctx sdk.Context, evm *vm.EVM, st
return method.Outputs.Pack()
}

func (d *DASignersPrecompile) UpdateSocket(ctx sdk.Context, evm *vm.EVM, stateDB *statedb.StateDB, method *abi.Method, args []interface{}) ([]byte, error) {
msg, err := NewMsgUpdateSocket(args, ToLowerHexWithoutPrefix(evm.Origin))
func (d *DASignersPrecompile) UpdateSocket(
ctx sdk.Context,
evm *vm.EVM,
stateDB *statedb.StateDB,
contract *vm.Contract,
method *abi.Method,
args []interface{},
) ([]byte, error) {
msg, err := NewMsgUpdateSocket(args, precopmiles_common.ToLowerHexWithoutPrefix(evm.Origin))
if err != nil {
return nil, err
}
// validation
if contract.CallerAddress != evm.Origin {
return nil, fmt.Errorf(precopmiles_common.ErrSenderNotOrigin)
}
// execute
_, err = d.dasignersKeeper.UpdateSocket(sdk.WrapSDKContext(ctx), msg)
if err != nil {
Expand Down
9 changes: 2 additions & 7 deletions precompiles/dasigners/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package dasigners
import (
"fmt"
"math/big"
"strings"

precopmiles_common "github.com/0glabs/0g-chain/precompiles/common"
dasignerstypes "github.com/0glabs/0g-chain/x/dasigners/v1/types"
Expand Down Expand Up @@ -90,7 +89,7 @@ func NewQuerySignerRequest(args []interface{}) (*dasignerstypes.QuerySignerReque
Accounts: make([]string, len(accounts)),
}
for i, account := range accounts {
req.Accounts[i] = ToLowerHexWithoutPrefix(account)
req.Accounts[i] = precopmiles_common.ToLowerHexWithoutPrefix(account)
}
return &req, nil
}
Expand Down Expand Up @@ -139,10 +138,6 @@ func NewIDASignersSignerDetail(signer *dasignerstypes.Signer) IDASignersSignerDe
}
}

func ToLowerHexWithoutPrefix(addr common.Address) string {
return strings.ToLower(addr.Hex()[2:])
}

func NewMsgRegisterSigner(args []interface{}) (*dasignerstypes.MsgRegisterSigner, error) {
if len(args) != 2 {
return nil, fmt.Errorf(precopmiles_common.ErrInvalidNumberOfArgs, 2, len(args))
Expand All @@ -151,7 +146,7 @@ func NewMsgRegisterSigner(args []interface{}) (*dasignerstypes.MsgRegisterSigner
signer := args[0].(IDASignersSignerDetail)
return &dasignerstypes.MsgRegisterSigner{
Signer: &dasignerstypes.Signer{
Account: ToLowerHexWithoutPrefix(signer.Signer),
Account: precopmiles_common.ToLowerHexWithoutPrefix(signer.Signer),
Socket: signer.Socket,
PubkeyG1: SerializeG1(signer.PkG1),
PubkeyG2: SerializeG2(signer.PkG2),
Expand Down
18 changes: 18 additions & 0 deletions precompiles/interfaces/.solhint.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"extends": "solhint:recommended",
"plugins": ["prettier"],
"rules": {
"avoid-low-level-calls": "off",
"compiler-version": "off",
"gas-custom-errors": "off",
"explicit-types": ["warn", "implicit"],
"func-visibility": ["warn", { "ignoreConstructors": true }],
"max-states-count": "off",
"no-empty-blocks": "off",
"no-global-import": "off",
"no-inline-assembly": "off",
"not-rely-on-time": "off",
"prettier/prettier": "error",
"reason-string": "off"
}
}
88 changes: 88 additions & 0 deletions precompiles/interfaces/contracts/IDASigners.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity >=0.8.0;

library BN254 {
struct G1Point {
uint X;
uint Y;
}

// Encoding of field elements is: X[1] * i + X[0]
struct G2Point {
uint[2] X;
uint[2] Y;
}
}

interface IDASigners {
/*=== struct ===*/
struct SignerDetail {
address signer;
string socket;
BN254.G1Point pkG1;
BN254.G2Point pkG2;
}

struct Params {
uint tokensPerVote;
uint maxVotesPerSigner;
uint maxQuorums;
uint epochBlocks;
uint encodedSlices;
}

/*=== event ===*/
event NewSigner(
address indexed signer,
BN254.G1Point pkG1,
BN254.G2Point pkG2
);
event SocketUpdated(address indexed signer, string socket);

/*=== function ===*/
function params() external view returns (Params memory);

function epochNumber() external view returns (uint);

function quorumCount(uint _epoch) external view returns (uint);

function isSigner(address _account) external view returns (bool);

function getSigner(
address[] memory _account
) external view returns (SignerDetail[] memory);

function getQuorum(
uint _epoch,
uint _quorumId
) external view returns (address[] memory);

function getQuorumRow(
uint _epoch,
uint _quorumId,
uint32 _rowIndex
) external view returns (address);

function registerSigner(
SignerDetail memory _signer,
BN254.G1Point memory _signature
) external;

function updateSocket(string memory _socket) external;

function registeredEpoch(
address _account,
uint _epoch
) external view returns (bool);

function registerNextEpoch(BN254.G1Point memory _signature) external;

function getAggPkG1(
uint _epoch,
uint _quorumId,
bytes memory _quorumBitmap
)
external
view
returns (BN254.G1Point memory aggPkG1, uint total, uint hit);
}
Loading

0 comments on commit 76eebc5

Please sign in to comment.