Skip to content

Commit

Permalink
Add forkchainSigner
Browse files Browse the repository at this point in the history
  • Loading branch information
dyng committed Mar 3, 2023
1 parent 89d88e8 commit 8591858
Show file tree
Hide file tree
Showing 2 changed files with 141 additions and 2 deletions.
121 changes: 119 additions & 2 deletions internal/provider/ethereum.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/dyng/ramen/internal/common/conv"
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethclient"
Expand Down Expand Up @@ -41,7 +42,6 @@ type txExtraInfo struct {
BlockNumber *string `json:"blockNumber,omitempty"`
BlockHash *common.Hash `json:"blockHash,omitempty"`
From *common.Address `json:"from,omitempty"`
TransactionIndex uint `json:"transactionIndex,omitempty"`
Timestamp uint64 `json:"timeStamp,omitempty"`
}

Expand All @@ -57,6 +57,83 @@ func (tx *rpcTransaction) ToTransaction() common.Transaction {
return common.WrapTransaction(tx.tx, big.NewInt(blockNumer), tx.From, tx.Timestamp)
}

type rpcBlock struct {
*types.Header
rpcBlockBody
}

type rpcBlockBody struct {
Hash common.Hash `json:"hash"`
Transactions []rpcTransaction `json:"transactions"`
UncleHashes []common.Hash `json:"uncles"`
}

func (b *rpcBlock) UnmarshalJSON(msg []byte) error {
if err := json.Unmarshal(msg, &b.Header); err != nil {
return errors.WithStack(err)
}
if err := json.Unmarshal(msg, &b.rpcBlockBody); err != nil {
return errors.WithStack(err)
}
return nil
}

func (b *rpcBlock) ToBlock() *common.Block {
txns := make(types.Transactions, len(b.Transactions))
for i, tx := range b.Transactions {
txns[i] = tx.tx
}
return types.NewBlockWithHeader(b.Header).WithBody(txns, []*types.Header{})
}

// forkchainSigner is a signer handles mixed transactions of different chains (often the case of local fork chain)
type forkchainSigner struct {
chainId *big.Int
signers map[uint64]types.Signer
}

func newForkchainSigner(chainId *big.Int) types.Signer {
return &forkchainSigner{
chainId: chainId,
signers: make(map[uint64]types.Signer),
}
}

func (s forkchainSigner) getSigner(tx *types.Transaction) types.Signer {
signer, ok := s.signers[tx.ChainId().Uint64()]
if !ok {
signer = types.NewLondonSigner(tx.ChainId())
s.signers[tx.ChainId().Uint64()] = signer
}
return signer
}

// ChainID implements types.Signer
func (s forkchainSigner) ChainID() *big.Int {
return s.chainId
}

// Equal implements types.Signer
func (s forkchainSigner) Equal(s2 types.Signer) bool {
x, ok := s2.(forkchainSigner)
return ok && x.chainId.Cmp(s.chainId) == 0
}

// Hash implements types.Signer
func (s forkchainSigner) Hash(tx *types.Transaction) common.Hash {
return s.getSigner(tx).Hash(tx)
}

// Sender implements types.Signer
func (s forkchainSigner) Sender(tx *types.Transaction) (common.Address, error) {
return s.getSigner(tx).Sender(tx)
}

// SignatureValues implements types.Signer
func (s forkchainSigner) SignatureValues(tx *types.Transaction, sig []byte) (R *big.Int, S *big.Int, V *big.Int, err error) {
return s.getSigner(tx).SignatureValues(tx, sig)
}

type Provider struct {
url string
providerType string
Expand Down Expand Up @@ -101,7 +178,7 @@ func (p *Provider) GetNetwork() (common.BigInt, error) {
return nil, errors.WithStack(err)
}
p.chainId = chainId
p.signer = types.NewLondonSigner(chainId)
p.signer = newForkchainSigner(chainId)
}
return p.chainId, nil
}
Expand Down Expand Up @@ -156,6 +233,35 @@ func (p *Provider) GetBlockByNumber(number common.BigInt) (*common.Block, error)
return block, errors.WithStack(err)
}

func (p *Provider) BatchBlockByNumber(numberList []common.BigInt) ([]*common.Block, error) {
size := len(numberList)
rpcRes := make([]rpcBlock, size)
reqs := make([]rpc.BatchElem, size)
for i := range reqs {
reqs[i] = rpc.BatchElem{
Method: "eth_getBlockByNumber",
Args: []any{toBlockNumArg(numberList[i]), true},
Result: &rpcRes[i],
}
}

ctx, cancel := p.createContext()
defer cancel()

err := p.rpcClient.BatchCallContext(ctx, reqs)
if err != nil {
return nil, errors.WithStack(err)
}

result := make([]*common.Block, size)
for i := range result {
result[i] = rpcRes[i].ToBlock()
}

// FIXME: individual request error handling
return result, nil
}

func (p *Provider) BatchTransactionByHash(hashList []common.Hash) (common.Transactions, error) {
size := len(hashList)
rpcRes := make([]rpcTransaction, size)
Expand Down Expand Up @@ -279,3 +385,14 @@ func (p *Provider) SubscribeNewHead(ch chan<- *common.Header) (ethereum.Subscrip
func (p *Provider) createContext() (context.Context, context.CancelFunc) {
return context.WithTimeout(context.Background(), DefaultTimeout)
}

func toBlockNumArg(number *big.Int) string {
if number == nil {
return "latest"
}
pending := big.NewInt(-1)
if number.Cmp(pending) == 0 {
return "pending"
}
return hexutil.EncodeBig(number)
}
22 changes: 22 additions & 0 deletions internal/provider/etherum_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,28 @@ func TestBatchTransactionByHash_NoError(t *testing.T) {
}
}

func TestBatchBlockByNumber_NoError(t *testing.T) {
// prepare
provider := NewProvider(testAlchemyEndpoint, ProviderAlchemy)

// process
numberList := []common.BigInt{
big.NewInt(16748002),
big.NewInt(16748001),
big.NewInt(16748000),
}
blocks, err := provider.BatchBlockByNumber(numberList)

// verify
assert.NoError(t, err)
assert.Len(t, blocks, 3)
for _, block := range blocks {
assert.NotNil(t, block.Number(), "block number should not be nil")
assert.NotNil(t, block.Hash(), "hash should not be nil")
assert.NotEmpty(t, block.Transactions(), "transactions should not be empty")
}
}

func TestCallContract_NoError(t *testing.T) {
// prepare
provider := NewProvider(testAlchemyEndpoint, ProviderAlchemy)
Expand Down

0 comments on commit 8591858

Please sign in to comment.