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

ethrpc: support nodes which return invalid vrs in no-strict mode #148

Merged
merged 1 commit into from
Nov 28, 2024
Merged
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
98 changes: 98 additions & 0 deletions cmd/chain-ethgas/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package main

import (
"context"
"fmt"
"log"
"time"

"github.com/0xsequence/ethkit/ethgas"
"github.com/0xsequence/ethkit/ethmonitor"
"github.com/0xsequence/ethkit/ethrpc"
"github.com/0xsequence/ethkit/util"
"github.com/goware/logger"
)

var ETH_NODE_URL = "http://localhost:8545"
var ETH_NODE_WSS_URL = ""

func init() {
testConfig, err := util.ReadTestConfig("../../ethkit-test.json")
if err != nil {
panic(err)
}

if testConfig["POLYGON_MAINNET_URL"] != "" {
ETH_NODE_URL = testConfig["POLYGON_MAINNET_URL"]
ETH_NODE_WSS_URL = testConfig["POLYGON_MAINNET_WSS_URL"]
}
// if testConfig["MAINNET_URL"] != "" {
// ETH_NODE_URL = testConfig["MAINNET_URL"]
// ETH_NODE_WSS_URL = testConfig["MAINNET_WSS_URL"]
// }

// ETH_NODE_URL = ""
// ETH_NODE_WSS_URL = ""
}

func main() {
fmt.Println("chain-ethgas start")

// Provider
provider, err := ethrpc.NewProvider(ETH_NODE_URL, ethrpc.WithStreaming(ETH_NODE_WSS_URL))
if err != nil {
log.Fatal(err)
}

// Monitor options
monitorOptions := ethmonitor.DefaultOptions
monitorOptions.PollingInterval = time.Duration(1000 * time.Millisecond)
// monitorOptions.DebugLogging = true
monitorOptions.WithLogs = true
monitorOptions.BlockRetentionLimit = 400
monitorOptions.StartBlockNumber = nil // track the head

// ...
monitor, err := ethmonitor.NewMonitor(provider, monitorOptions)
if err != nil {
log.Fatal(err)
}

ctx := context.Background()

go func() {
err = monitor.Run(ctx)
if err != nil {
panic(err)
}
}()
defer monitor.Stop()

logger := logger.NewLogger(logger.LogLevel_INFO)

gasGague, err := ethgas.NewGasGauge(logger, monitor, 1, false)
if err != nil {
log.Fatal(err)
}

go func() {
err := gasGague.Run(ctx)
if err != nil {
log.Fatal(err)
}
}()
defer gasGague.Stop()

sub := gasGague.Subscribe()
defer sub.Unsubscribe()

for {
select {
case <-sub.Blocks():
prices := gasGague.SuggestedGasPrice()
bids := gasGague.SuggestedGasPriceBid()
fmt.Println(prices.BlockNum, prices.BlockTime, prices.Instant, prices.Fast, prices.Standard, prices.Slow)
fmt.Println(bids.BlockNum, bids.BlockTime, bids.Instant, bids.Fast, bids.Standard, bids.Slow)
}
}
}
18 changes: 18 additions & 0 deletions ethrpc/ethrpc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -305,3 +305,21 @@ func TestDebugTraceTransaction(t *testing.T) {
// require.NotNil(t, block)
// require.Equal(t, uint64(1_000_000), block.NumberU64())
// }

func TestFetchBlockWithInvalidVRS(t *testing.T) {
url := "https://rpc.telos.net"
// url := "https://node.mainnet.etherlink.com"

p, err := ethrpc.NewProvider(url)
require.NoError(t, err)

block, err := p.BlockByNumber(context.Background(), big.NewInt(373117692))
require.NoError(t, err)
require.NotNil(t, block)

for _, tx := range block.Transactions() {
require.Equal(t, uint8(0), tx.Type())
require.Equal(t, big.NewInt(0), tx.GasFeeCap())
require.Equal(t, big.NewInt(0), tx.GasPrice())
}
}
32 changes: 30 additions & 2 deletions ethrpc/unmarshal.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,18 @@ func (tx *rpcTransaction) UnmarshalJSON(msg []byte) error {
// we set internal flag to check if txn has invalid VRS signature
if err == types.ErrInvalidSig {
tx.txVRSInvalid = true

// reset vrs to 0x0 and try again. we perform validation in the caller
msg, err = resetVRS(msg)
if err != nil {
return err
}

// in case of any other error, return the error
err = json.Unmarshal(msg, &tx.tx)
if err != nil {
return err
}
}
}

Expand Down Expand Up @@ -103,7 +115,7 @@ func IntoBlock(raw json.RawMessage, ret **types.Block, strictness StrictnessLeve
}

if strictness >= StrictnessLevel_Semi && tx.txVRSInvalid {
return fmt.Errorf("invalid transaction v, r, s")
return types.ErrInvalidSig
}

if tx.txExtraInfo.TxType != "" {
Expand Down Expand Up @@ -160,7 +172,7 @@ func IntoTransactionWithPending(raw json.RawMessage, tx **types.Transaction, pen

if strictness >= StrictnessLevel_Semi {
if body.txVRSInvalid {
return fmt.Errorf("invalid transaction v, r, s")
return types.ErrInvalidSig
}
if _, r, _ := body.tx.RawSignatureValues(); r == nil {
return fmt.Errorf("server returned transaction without signature")
Expand Down Expand Up @@ -217,3 +229,19 @@ func (s *senderFromServer) Hash(tx *types.Transaction) common.Hash {
func (s *senderFromServer) SignatureValues(tx *types.Transaction, sig []byte) (R, S, V *big.Int, err error) {
panic("can't sign with senderFromServer")
}

func resetVRS(msg []byte) ([]byte, error) {
var m map[string]interface{}
err := json.Unmarshal(msg, &m)
if err != nil {
return nil, err
}
m["v"] = "0x0"
m["r"] = "0x0"
m["s"] = "0x0"
out, err := json.Marshal(m)
if err != nil {
return nil, err
}
return out, nil
}