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

WIP - Fork level Epoch #102

Draft
wants to merge 8 commits into
base: sxbet-validators/data-oracle-toronto
Choose a base branch
from
Draft
Show file tree
Hide file tree
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
7 changes: 7 additions & 0 deletions command/ibft/switch/ibft_switch.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,13 @@ func setFlags(cmd *cobra.Command) {
"",
"the custom contract address to use for SC interaction",
)

cmd.Flags().Uint64Var(
&params.forkEpochSizeRaw,
forkEpochSize,
0,
"fork-level epoch, overrides ibft epochSize for hook-related logic",
)
}

func runPreRun(_ *cobra.Command, _ []string) error {
Expand Down
14 changes: 13 additions & 1 deletion command/ibft/switch/params.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ const (
minValidatorCount = "min-validator-count"
maxValidatorCount = "max-validator-count"
customContractAddress = "custom-contract-address"
forkEpochSize = "fork-epoch"
)

var (
Expand Down Expand Up @@ -48,6 +49,8 @@ type switchParams struct {
minValidatorCount *uint64

customContractAddressRaw string

forkEpochSizeRaw uint64
}

func (p *switchParams) getRequiredFlags() []string {
Expand Down Expand Up @@ -214,6 +217,7 @@ func (p *switchParams) updateGenesisConfig() error {
p.maxValidatorCount,
p.minValidatorCount,
p.customContractAddressRaw,
p.forkEpochSizeRaw,
)
}

Expand All @@ -240,6 +244,7 @@ func (p *switchParams) getResult() command.CommandResult {
Type: p.mechanismType,
From: common.JSONNumber{Value: p.from},
CustomContractAddress: p.customContractAddressRaw,
ForkEpochSize: p.forkEpochSizeRaw,
}

if p.deployment != nil {
Expand All @@ -262,6 +267,8 @@ func (p *switchParams) getResult() command.CommandResult {
result.CustomContractAddress = p.customContractAddressRaw
}

result.ForkEpochSize = p.forkEpochSizeRaw

return result
}

Expand All @@ -273,6 +280,8 @@ func appendIBFTForks(
maxValidatorCount *uint64,
minValidatorCount *uint64,
customContractAddress string,
forkEpochSize uint64,

) error {
ibftConfig, ok := cc.Params.Engine["ibft"].(map[string]interface{})
if !ok {
Expand All @@ -285,7 +294,9 @@ func appendIBFTForks(
}

lastFork := &ibftForks[len(ibftForks)-1]
if mechanismType == lastFork.Type && customContractAddress == lastFork.CustomContractAddress {
if mechanismType == lastFork.Type &&
customContractAddress == lastFork.CustomContractAddress &&
forkEpochSize == lastFork.ForkEpochSize {
return errors.New(`cannot specify same IBFT type to the last fork`)
}

Expand All @@ -299,6 +310,7 @@ func appendIBFTForks(
Type: mechanismType,
From: common.JSONNumber{Value: from},
CustomContractAddress: customContractAddress,
ForkEpochSize: forkEpochSize,
}

if mechanismType == ibft.PoS {
Expand Down
2 changes: 2 additions & 0 deletions command/ibft/switch/result.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ type IBFTSwitchResult struct {
MaxValidatorCount common.JSONNumber `json:"maxValidatorCount"`
MinValidatorCount common.JSONNumber `json:"minValidatorCount"`
CustomContractAddress string `json:"customContractAddress"`
ForkEpochSize uint64 `json:"forkEpochSize"`
}

func (r *IBFTSwitchResult) GetOutput() string {
Expand All @@ -40,6 +41,7 @@ func (r *IBFTSwitchResult) GetOutput() string {
outputs = append(outputs, fmt.Sprint("CustomContractAddress|", r.CustomContractAddress))
}

outputs = append(outputs, fmt.Sprint("ForkEpochSize|", r.ForkEpochSize))
buffer.WriteString(helper.FormatKV(outputs))
buffer.WriteString("\n")

Expand Down
10 changes: 10 additions & 0 deletions consensus/ibft/extra.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,16 @@ func getIbftExtra(h *types.Header) (*IstanbulExtra, error) {
return extra, nil
}

// getIbftExtraValidators returns the validator set from the header extraData at specified height
func (i *backendIBFT) getIbftExtraValidators(header *types.Header) ([]types.Address, error) {
extra, err := getIbftExtra(header)
if err != nil {
return nil, err
}

return extra.Validators, nil
}

// IstanbulExtra defines the structure of the extra field for Istanbul
type IstanbulExtra struct {
Validators []types.Address
Expand Down
14 changes: 11 additions & 3 deletions consensus/ibft/hooks.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,9 @@ type ConsensusMechanism interface {

// gets the custom contract address for the current mechanism
getCustomContractAddress() types.Address

// fork-specific epochSize
getForkEpoch() uint64
}

type BaseConsensusMechanism struct {
Expand All @@ -116,6 +119,9 @@ type BaseConsensusMechanism struct {

// Custom contract address
CustomContractAddress types.Address

// fork-specific epochSize
ForkEpochSize uint64
}

// initializeParams initializes mechanism parameters from chain config
Expand Down Expand Up @@ -143,6 +149,8 @@ func (base *BaseConsensusMechanism) initializeParams(params *IBFTFork) error {
base.CustomContractAddress = types.StringToAddress(params.CustomContractAddress)
// base.ibft.customContractAddress = types.StringToAddress(params.CustomContractAddress)

base.ForkEpochSize = params.ForkEpochSize

return nil
}

Expand Down Expand Up @@ -180,6 +188,7 @@ type IBFTFork struct {
MaxValidatorCount *common.JSONNumber `json:"maxValidatorCount,omitempty"`
MinValidatorCount *common.JSONNumber `json:"minValidatorCount,omitempty"`
CustomContractAddress string `json:"customContractAddress,omitempty"`
ForkEpochSize uint64 `json:"forkEpochSize,omitempty"`
}

// ConsensusMechanismFactory is the factory function to create a consensus mechanism
Expand All @@ -192,7 +201,6 @@ var mechanismBackends = map[MechanismType]ConsensusMechanismFactory{

// preStateCommitHookParams are the params passed into the preStateCommitHook
type preStateCommitHookParams struct {
header *types.Header
txn *state.Transition
validatorSet ValidatorSet
header *types.Header
txn *state.Transition
}
33 changes: 24 additions & 9 deletions consensus/ibft/ibft.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ var (
ErrInvalidHookParam = errors.New("invalid IBFT hook param passed in")
)

type forkConfig struct {
customContract types.Address
forkEpoch uint64
}

type txPoolInterface interface {
Prepare()
Length() uint64
Expand Down Expand Up @@ -168,17 +173,23 @@ func (i *backendIBFT) runHook(hookName HookType, height uint64, hookParam interf
return nil
}

// getCustomContractAddressFromCurrentFork returns the customContractAddress from the current fork
func (i *backendIBFT) getCustomContractAddressFromCurrentFork(height uint64) types.Address {
// getCurrentForkConfig returns the current forkConfig
func (i *backendIBFT) getCurrentForkConfig(height uint64) forkConfig {
for _, mechanism := range i.mechanisms {
if !mechanism.isCurrent(height) {
continue
}

return mechanism.getCustomContractAddress()
return forkConfig{
customContract: mechanism.getCustomContractAddress(),
forkEpoch: mechanism.getForkEpoch(),
}
}

return types.ZeroAddress
return forkConfig{
customContract: types.ZeroAddress,
forkEpoch: 0,
}
}

func (i *backendIBFT) Initialize() error {
Expand Down Expand Up @@ -561,9 +572,8 @@ func (i *backendIBFT) GetBlockCreator(header *types.Header) (types.Address, erro
// PreStateCommit a hook to be called before finalizing state transition on inserting block
func (i *backendIBFT) PreStateCommit(header *types.Header, txn *state.Transition) error {
params := &preStateCommitHookParams{
header: header,
txn: txn,
validatorSet: i.activeValidatorSet,
header: header,
txn: txn,
}

if err := i.runHook(PreStateCommitHook, header.Number, params); err != nil {
Expand All @@ -584,7 +594,12 @@ func (i *backendIBFT) GetEpoch(number uint64) uint64 {

// IsLastOfEpoch checks if the block number is the last of the epoch
func (i *backendIBFT) IsLastOfEpoch(number uint64) bool {
return number > 0 && number%i.epochSize == 0
forkEpoch := i.getCurrentForkConfig(number).forkEpoch
if forkEpoch == 0 {
return number > 0 && number%i.epochSize == 0
}

return number > 0 && number%forkEpoch == 0
}

// Close closes the IBFT consensus mechanism, and does write back to disk
Expand Down Expand Up @@ -628,7 +643,7 @@ func (i *backendIBFT) getConsensusInfoImpl() *consensus.ConsensusInfo {
ValidatorAddress: i.validatorKeyAddr,
Epoch: i.GetEpoch(i.blockchain.Header().Number),
QuorumSize: i.quorumSize(i.blockchain.Header().Number)(i.activeValidatorSet),
CustomContractAddress: i.getCustomContractAddressFromCurrentFork(i.blockchain.Header().Number),
CustomContractAddress: i.getCurrentForkConfig(i.blockchain.Header().Number).customContract,
Nonce: i.txpool.GetNonce(i.validatorKeyAddr),
}
}
17 changes: 12 additions & 5 deletions consensus/ibft/poa.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,7 @@ func (poa *PoAMechanism) IsAvailable(hookType HookType, height uint64) bool {
case VerifyHeadersHook, ProcessHeadersHook, CandidateVoteHook:
return poa.IsInRange(height)
case PreStateCommitHook:
return poa.CustomContractAddress != types.ZeroAddress &&
(height+1 == poa.From || poa.IsInRange(height) && poa.ibft.IsLastOfEpoch(height))
return poa.CustomContractAddress != types.ZeroAddress && (poa.IsInRange(height) && poa.ibft.IsLastOfEpoch(height))
default:
return false
}
Expand All @@ -67,6 +66,10 @@ func (poa *PoAMechanism) getCustomContractAddress() types.Address {
return poa.CustomContractAddress
}

func (poa *PoAMechanism) getForkEpoch() uint64 {
return poa.ForkEpochSize
}

// verifyHeadersHook verifies that the header nonce conforms to the IBFT PoA proposal format
func (poa *PoAMechanism) verifyHeadersHook(nonceParam interface{}) error {
// Cast the param to the nonce
Expand Down Expand Up @@ -232,10 +235,14 @@ func (poa *PoAMechanism) preStateCommitHook(rawParams interface{}) error {
return ErrInvalidHookParam
}

poa.ibft.logger.Debug("preStateCommitHook - calling setValidators here..")
snap := poa.ibft.getSnapshot(params.header.Number)
validators, ibftExtraErr := poa.ibft.getIbftExtraValidators(params.header)
if ibftExtraErr != nil {
return ibftExtraErr
}

poa.ibft.logger.Debug("preStateCommitHook - calling setValidators here..", "validators", validators)

_, err := datafeed.SetValidators(params.txn, types.ZeroAddress, poa.CustomContractAddress, snap.Set)
_, err := datafeed.SetValidators(params.txn, types.ZeroAddress, poa.CustomContractAddress, validators)
if err != nil {
poa.ibft.logger.Error("failed to call setValidators", "err", err)
}
Expand Down
4 changes: 4 additions & 0 deletions consensus/ibft/pos.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ func (pos *PoSMechanism) getCustomContractAddress() types.Address {
return pos.CustomContractAddress
}

func (pos *PoSMechanism) getForkEpoch() uint64 {
return pos.ForkEpochSize
}

// initializeParams initializes mechanism parameters from chain config
func (pos *PoSMechanism) initializeParams(params *IBFTFork) error {
if err := pos.BaseConsensusMechanism.initializeParams(params); err != nil {
Expand Down
1 change: 0 additions & 1 deletion consensus/ibft/verifier.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ func (i *backendIBFT) IsValidBlock(proposal []byte) bool {
}

if err := i.runHook(VerifyBlockHook, newBlock.Number(), newBlock); err != nil {
//nolint:govet
if errors.As(err, &errBlockVerificationFailed) {
i.logger.Error("block verification fail, block at the end of epoch has transactions")
} else {
Expand Down
4 changes: 2 additions & 2 deletions datafeed/datafeed.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,10 +99,10 @@ func NewDataFeedService(
}

if config.VerifyOutcomeURI == "" && config.MQConfig.AMQPURI == "" {
logger.Warn("DataFeed 'verify_outcome_api_url' is missing but required for reporting - we will avoid participating in reporting gossiping")
logger.Warn("DataFeed 'verify_outcome_api_url' is missing but required for reporting - we will avoid participating in reporting gossiping") //nolint:lll

return datafeedService, nil
}

// configure libp2p
if network == nil {
return nil, fmt.Errorf("network must be non-nil to start gossip protocol")
Expand Down
1 change: 0 additions & 1 deletion datafeed/validations.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,6 @@ func (d *DataFeed) validateTimestamp(payload *proto.DataFeedReport) bool {
func (d *DataFeed) validateSignatures(payload *proto.DataFeedReport) (bool, error) {
sigList := strings.Split(payload.Signatures, ",")
for _, sig := range sigList {

pub, err := d.signatureToAddress(payload, sig)

if err != nil {
Expand Down
1 change: 1 addition & 0 deletions e2e/datafeed_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ func TestReportOutcome(t *testing.T) {
t.Logf("sig1 %s", sig1)

t.Logf("hashedReport1: %s", hex.EncodeToHex(hashed1))

sig1Decoded[64] = sig1Decoded[64] - 27

pub, err := cryptoutils.SigToPub(hashed1, sig1Decoded)
Expand Down
8 changes: 1 addition & 7 deletions jsonrpc/eth_endpoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ var (
)

// ChainId returns the chain id of the client
//nolint:stylecheck, gofmt
//nolint:stylecheck
func (e *Eth) ChainId() (interface{}, error) {
return argUintPtr(e.chainID), nil
}
Expand Down Expand Up @@ -407,7 +407,6 @@ func (e *Eth) GetStorageAt(
// Get the storage for the passed in location
result, err := e.store.GetStorage(header.StateRoot, address, index)
if err != nil {
//nolint:govet
if errors.As(err, &ErrStateNotFound) {
return argBytesPtr(types.ZeroHash[:]), nil
}
Expand Down Expand Up @@ -540,7 +539,6 @@ func (e *Eth) EstimateGas(arg *txnArgs, rawNum *BlockNumber) (interface{}, error
accountBalance := big.NewInt(0)
acc, err := e.store.GetAccount(header.StateRoot, transaction.From)

//nolint:govet
if err != nil && !errors.As(err, &ErrStateNotFound) {
// An unrelated error occurred, return it
return nil, err
Expand Down Expand Up @@ -584,7 +582,6 @@ func (e *Eth) EstimateGas(arg *txnArgs, rawNum *BlockNumber) (interface{}, error
// Checks if executor level valid gas errors occurred
isGasApplyError := func(err error) bool {
// Not linting this as the underlying error is actually wrapped
//nolint:govet
return errors.As(err, &state.ErrNotEnoughIntrinsicGas)
}

Expand Down Expand Up @@ -711,7 +708,6 @@ func (e *Eth) GetBalance(address types.Address, filter BlockNumberOrHash) (inter

// Extract the account balance
acc, err := e.store.GetAccount(header.StateRoot, address)
//nolint:govet
if errors.As(err, &ErrStateNotFound) {
// Account not found, return an empty account
return argUintPtr(0), nil
Expand Down Expand Up @@ -778,7 +774,6 @@ func (e *Eth) GetCode(address types.Address, filter BlockNumberOrHash) (interfac
emptySlice := []byte{}
acc, err := e.store.GetAccount(header.StateRoot, address)

//nolint:govet
if errors.As(err, &ErrStateNotFound) {
// If the account doesn't exist / is not initialized yet,
// return the default value
Expand Down Expand Up @@ -869,7 +864,6 @@ func (e *Eth) getNextNonce(address types.Address, number BlockNumber) (uint64, e

acc, err := e.store.GetAccount(header.StateRoot, address)

//nolint:govet
if errors.As(err, &ErrStateNotFound) {
// If the account doesn't exist / isn't initialized,
// return a nonce value of 0
Expand Down
2 changes: 1 addition & 1 deletion state/runtime/precompiled/base_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//nolint: lll,gofmt
//nolint: lll
package precompiled

import (
Expand Down
2 changes: 1 addition & 1 deletion syncer/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -371,7 +371,7 @@ func TestPeerConnectionUpdateEventCh(t *testing.T) {
// Make sure the peer shouldn't emit status if the shouldEmitBlocks flag is set.
// The subtests cannot contain t.Parallel() due to how
// the test is organized
//nolint:tparallel, gofmt
//nolint:tparallel
func Test_shouldEmitBlocks(t *testing.T) {
t.Parallel()

Expand Down