diff --git a/cmd/chain-ethgas/main.go b/cmd/chain-ethgas/main.go new file mode 100644 index 0000000..2ba19ed --- /dev/null +++ b/cmd/chain-ethgas/main.go @@ -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) + } + } +} diff --git a/ethrpc/ethrpc_test.go b/ethrpc/ethrpc_test.go index 2c3b884..f2dd32c 100644 --- a/ethrpc/ethrpc_test.go +++ b/ethrpc/ethrpc_test.go @@ -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()) + } +} diff --git a/ethrpc/unmarshal.go b/ethrpc/unmarshal.go index b88b579..0786bdc 100644 --- a/ethrpc/unmarshal.go +++ b/ethrpc/unmarshal.go @@ -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 + } } } @@ -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 != "" { @@ -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") @@ -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 +}