Skip to content

Commit

Permalink
add support for backwards mode in avalanche subnets (#12039)
Browse files Browse the repository at this point in the history
  • Loading branch information
jinhoonbang authored Feb 16, 2024
1 parent cce6c80 commit da02459
Show file tree
Hide file tree
Showing 2 changed files with 151 additions and 4 deletions.
126 changes: 126 additions & 0 deletions core/scripts/common/avalanche_subnet.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
package common

import (
"encoding/json"
"errors"
"math/big"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
)

// AvaSubnetHeader is a copy of [github.com/ava-labs/subnet-evm/core/types.Header] to avoid importing the whole module.
type AvaSubnetHeader struct {
ParentHash common.Hash `json:"parentHash" gencodec:"required"`
UncleHash common.Hash `json:"sha3Uncles" gencodec:"required"`
Coinbase common.Address `json:"miner" gencodec:"required"`
Root common.Hash `json:"stateRoot" gencodec:"required"`
TxHash common.Hash `json:"transactionsRoot" gencodec:"required"`
ReceiptHash common.Hash `json:"receiptsRoot" gencodec:"required"`
Bloom AvaBloom `json:"logsBloom" gencodec:"required"`
Difficulty *big.Int `json:"difficulty" gencodec:"required"`
Number *big.Int `json:"number" gencodec:"required"`
GasLimit uint64 `json:"gasLimit" gencodec:"required"`
GasUsed uint64 `json:"gasUsed" gencodec:"required"`
Time uint64 `json:"timestamp" gencodec:"required"`
Extra []byte `json:"extraData" gencodec:"required"`
MixDigest common.Hash `json:"mixHash"`
Nonce AvaBlockNonce `json:"nonce"`
BaseFee *big.Int `json:"baseFeePerGas" rlp:"optional"`
BlockGasCost *big.Int `json:"blockGasCost" rlp:"optional"`
}

func (h *AvaSubnetHeader) UnmarshalJSON(input []byte) error {
type Header struct {
ParentHash *common.Hash `json:"parentHash" gencodec:"required"`
UncleHash *common.Hash `json:"sha3Uncles" gencodec:"required"`
Coinbase *common.Address `json:"miner" gencodec:"required"`
Root *common.Hash `json:"stateRoot" gencodec:"required"`
TxHash *common.Hash `json:"transactionsRoot" gencodec:"required"`
ReceiptHash *common.Hash `json:"receiptsRoot" gencodec:"required"`
Bloom *AvaBloom `json:"logsBloom" gencodec:"required"`
Difficulty *hexutil.Big `json:"difficulty" gencodec:"required"`
Number *hexutil.Big `json:"number" gencodec:"required"`
GasLimit *hexutil.Uint64 `json:"gasLimit" gencodec:"required"`
GasUsed *hexutil.Uint64 `json:"gasUsed" gencodec:"required"`
Time *hexutil.Uint64 `json:"timestamp" gencodec:"required"`
Extra *hexutil.Bytes `json:"extraData" gencodec:"required"`
MixDigest *common.Hash `json:"mixHash"`
Nonce *AvaBlockNonce `json:"nonce"`
BaseFee *hexutil.Big `json:"baseFeePerGas" rlp:"optional"`
BlockGasCost *hexutil.Big `json:"blockGasCost" rlp:"optional"`
}
var dec Header
if err := json.Unmarshal(input, &dec); err != nil {
return err
}
if dec.ParentHash == nil {
return errors.New("missing required field 'parentHash' for Header")
}
h.ParentHash = *dec.ParentHash
if dec.UncleHash == nil {
return errors.New("missing required field 'sha3Uncles' for Header")
}
h.UncleHash = *dec.UncleHash
if dec.Coinbase == nil {
return errors.New("missing required field 'miner' for Header")
}
h.Coinbase = *dec.Coinbase
if dec.Root == nil {
return errors.New("missing required field 'stateRoot' for Header")
}
h.Root = *dec.Root
if dec.TxHash == nil {
return errors.New("missing required field 'transactionsRoot' for Header")
}
h.TxHash = *dec.TxHash
if dec.ReceiptHash == nil {
return errors.New("missing required field 'receiptsRoot' for Header")
}
h.ReceiptHash = *dec.ReceiptHash
if dec.Bloom == nil {
return errors.New("missing required field 'logsBloom' for Header")
}
h.Bloom = *dec.Bloom
if dec.Difficulty == nil {
return errors.New("missing required field 'difficulty' for Header")
}
h.Difficulty = (*big.Int)(dec.Difficulty)
if dec.Number == nil {
return errors.New("missing required field 'number' for Header")
}
h.Number = (*big.Int)(dec.Number)
if dec.GasLimit == nil {
return errors.New("missing required field 'gasLimit' for Header")
}
h.GasLimit = uint64(*dec.GasLimit)
if dec.GasUsed == nil {
return errors.New("missing required field 'gasUsed' for Header")
}
h.GasUsed = uint64(*dec.GasUsed)
if dec.Time == nil {
return errors.New("missing required field 'timestamp' for Header")
}
h.Time = uint64(*dec.Time)
if dec.Extra == nil {
return errors.New("missing required field 'extraData' for Header")
}
h.Extra = *dec.Extra
if dec.MixDigest != nil {
h.MixDigest = *dec.MixDigest
}
if dec.Nonce != nil {
h.Nonce = *dec.Nonce
}
if dec.BaseFee != nil {
h.BaseFee = (*big.Int)(dec.BaseFee)
}
if dec.BlockGasCost != nil {
h.BlockGasCost = (*big.Int)(dec.BlockGasCost)
}
return nil
}

func (h *AvaSubnetHeader) Hash() common.Hash {
return rlpHash(h)
}
29 changes: 25 additions & 4 deletions core/scripts/common/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -498,7 +498,20 @@ func GetRlpHeaders(env Environment, blockNumbers []*big.Int, getParentBlocks boo
//fmt.Println("Calculated BH:", bh.String(),
// "fetched BH:", h.Hash(),
// "block number:", new(big.Int).Set(blockNum).Add(blockNum, offset).String())
} else if IsAvaxSubnet(env.ChainID) {
var h AvaSubnetHeader
// Get child block since it's the one that has the parent hash in its header.
nextBlockNum := new(big.Int).Set(blockNum).Add(blockNum, offset)
err2 := env.Jc.CallContext(context.Background(), &h, "eth_getBlockByNumber", hexutil.EncodeBig(nextBlockNum), false)
if err2 != nil {
return nil, hashes, fmt.Errorf("failed to get header: %+v", err2)
}
rlpHeader, err2 = rlp.EncodeToBytes(h)
if err2 != nil {
return nil, hashes, fmt.Errorf("failed to encode rlp: %+v", err2)
}

hashes = append(hashes, h.Hash().String())
} else if IsPolygonEdgeNetwork(env.ChainID) {

// Get child block since it's the one that has the parent hash in its header.
Expand Down Expand Up @@ -570,12 +583,20 @@ func CalculateLatestBlockHeader(env Environment, blockNumberInput int) (err erro
return err
}

// IsAvaxNetwork returns true if the given chain ID corresponds to an avalanche network or subnet.
// IsAvaxNetwork returns true if the given chain ID corresponds to an avalanche network.
func IsAvaxNetwork(chainID int64) bool {
return chainID == 43114 || // C-chain mainnet
chainID == 43113 || // Fuji testnet
chainID == 335 || // DFK testnet
chainID == 53935 // DFK mainnet
chainID == 43113 // Fuji testnet
}

// IsAvaxSubnet returns true if the given chain ID corresponds to an avalanche subnet.
func IsAvaxSubnet(chainID int64) bool {
return chainID == 335 || // DFK testnet
chainID == 53935 || // DFK mainnet
chainID == 955081 || // Nexon Dev
chainID == 595581 || // Nexon Test
chainID == 807424 || // Nexon QA
chainID == 847799 // Nexon Stage
}

func UpkeepLink(chainID int64, upkeepID *big.Int) string {
Expand Down

0 comments on commit da02459

Please sign in to comment.