Skip to content

Commit

Permalink
1559 (#230)
Browse files Browse the repository at this point in the history
* add cfx_maxPriorityFeePerGas and cfx_feeHistory

* pass integration tests

* modify tests

* update mock server url

* resolve comments

* update struct fields

* add change log
  • Loading branch information
wangdayong228 committed Jun 11, 2024
1 parent 927ea64 commit 2ced352
Show file tree
Hide file tree
Showing 18 changed files with 954 additions and 304 deletions.
9 changes: 9 additions & 0 deletions changeLog.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
Go-conflux-sdk Change Log
============

v1.6.0
------------
- Support 1559 related rpcs
- Return StoragePointProp in cfx_getParamsFromVote, which is introduced by CIP-107.

v1.5.9
------------
- Support circuit breaker when creating client

v1.5.9
------------
- Support circuit breaker when creating client
Expand Down
142 changes: 126 additions & 16 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package sdk

import (
"context"
"fmt"
"io"
"sync/atomic"

Expand Down Expand Up @@ -732,6 +733,22 @@ func (client *Client) GetPoSRewardByEpoch(epoch types.Epoch) (reward *postypes.E
return
}

// GetFeeHistory returns transaction base fee per gas and effective priority fee per gas for the requested/supported epoch range.
func (client *Client) GetFeeHistory(blockCount hexutil.Uint64, lastEpoch types.Epoch, rewardPercentiles []float64) (feeHistory *types.FeeHistory, err error) {
err = client.wrappedCallRPC(&feeHistory, "cfx_feeHistory", blockCount, lastEpoch, rewardPercentiles)
return
}

func (client *Client) GetMaxPriorityFeePerGas() (maxPriorityFeePerGas *hexutil.Big, err error) {
err = client.wrappedCallRPC(&maxPriorityFeePerGas, "cfx_maxPriorityFeePerGas")
return
}

func (client *Client) GetFeeBurnt(epoch ...*types.Epoch) (info *hexutil.Big, err error) {
err = client.wrappedCallRPC(&info, "cfx_getFeeBurnt", get1stEpochIfy(epoch))
return
}

// CreateUnsignedTransaction creates an unsigned transaction by parameters,
// and the other fields will be set to values fetched from conflux node.
func (client *Client) CreateUnsignedTransaction(from types.Address, to types.Address, amount *hexutil.Big, data []byte) (types.UnsignedTransaction, error) {
Expand Down Expand Up @@ -824,26 +841,125 @@ func (client *Client) ApplyUnsignedTransactionDefault(tx *types.UnsignedTransact
}
}

if tx.GasPrice == nil {
gasPrice, err := client.GetGasPrice()
if err != nil {
return errors.Wrap(err, "failed to get gas price")
if err := client.populateTxtypeAndGasPrice(tx); err != nil {
return err
}

tx.ApplyDefault()
}

return nil
}

func (client *Client) populateTxtypeAndGasPrice(tx *types.UnsignedTransaction) error {
if tx.GasPrice != nil && (tx.MaxFeePerGas != nil || tx.MaxPriorityFeePerGas != nil) {
return errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified")
}

if tx.GasPrice != nil && (tx.Type == nil || *tx.Type == types.TRANSACTION_TYPE_LEGACY) {
tx.Type = types.TRANSACTION_TYPE_LEGACY.Ptr()
return nil
}

has1559 := tx.MaxFeePerGas != nil || tx.MaxPriorityFeePerGas != nil

gasFeeData, err := client.getFeeData()
if err != nil {
return errors.Wrap(err, "failed to get fee data")
}

// set the txtype according to feeData
// - if support1559, then set txtype to 2
// - if not support1559
// - - if has maxFeePerGas or maxPriorityFeePerGas, then return error
// - - if contains accesslist, set txtype to 1
// - - else set txtype to 0
if tx.Type == nil {
if gasFeeData.isSupport1559() {
tx.Type = types.TRANSACTION_TYPE_1559.Ptr()
} else {
if has1559 {
return errors.New("not support 1559 but (maxFeePerGas or maxPriorityFeePerGas) specified")
}

// conflux responsed gasprice offen be 0, but the min gasprice is 1 when sending transaction, so do this
if gasPrice.ToInt().Cmp(big.NewInt(constants.MinGasprice)) < 1 {
gasPrice = types.NewBigInt(constants.MinGasprice)
if tx.AccessList == nil {
tx.Type = types.TRANSACTION_TYPE_LEGACY.Ptr()
} else {
tx.Type = types.TRANSACTION_TYPE_2930.Ptr()
}
tmp := hexutil.Big(*gasPrice)
tx.GasPrice = &tmp
}
}

tx.ApplyDefault()
// if txtype is DynamicFeeTxType that means support 1559, so if gasPrice is not nil, set max... to gasPrice
if *tx.Type == types.TRANSACTION_TYPE_1559 {
if tx.GasPrice != nil {
tx.MaxFeePerGas = tx.GasPrice
tx.MaxPriorityFeePerGas = tx.GasPrice
tx.GasPrice = nil
return nil
}

if tx.MaxPriorityFeePerGas == nil {
tx.MaxPriorityFeePerGas = (*hexutil.Big)(gasFeeData.maxPriorityFeePerGas)
}
if tx.MaxFeePerGas == nil {
tx.MaxFeePerGas = (*hexutil.Big)(gasFeeData.maxFeePerGas)
}
if tx.MaxFeePerGas.ToInt().Cmp(tx.MaxPriorityFeePerGas.ToInt()) < 0 {
return fmt.Errorf("maxFeePerGas (%v) < maxPriorityFeePerGas (%v)", tx.MaxFeePerGas, tx.MaxPriorityFeePerGas)
}
return nil
}

if tx.GasPrice != nil {
return nil
}

tx.GasPrice = (*hexutil.Big)(gasFeeData.gasPrice)
return nil
}

type gasFeeData struct {
gasPrice *hexutil.Big
maxFeePerGas *hexutil.Big
maxPriorityFeePerGas *hexutil.Big
}

func (g gasFeeData) isSupport1559() bool {
return g.maxPriorityFeePerGas != nil && g.maxFeePerGas != nil
}

func (client *Client) getFeeData() (*gasFeeData, error) {
data := &gasFeeData{}

gasPrice, err := client.GetGasPrice()
if err != nil {
return nil, err
}
data.gasPrice = gasPrice

block, err := client.GetBlockByEpoch(types.EpochLatestState)
if err != nil {
return nil, err
}
basefee := block.BaseFeePerGas

if basefee == nil {
return data, nil
}

priorityFeePerGas, err := client.GetMaxPriorityFeePerGas()
if err != nil {
return nil, err
}

data.maxPriorityFeePerGas = priorityFeePerGas
maxFeePerGas := new(big.Int).Mul(basefee.ToInt(), big.NewInt(2))
maxFeePerGas = new(big.Int).Add(maxFeePerGas, data.maxPriorityFeePerGas.ToInt())
data.maxFeePerGas = types.NewBigIntByRaw(maxFeePerGas)
return data, nil
}

// DeployContract deploys a contract by abiJSON, bytecode and consturctor params.
// It returns a ContractDeployState instance which contains 3 channels for notifying when state changed.
func (client *Client) DeployContract(option *types.ContractDeployOption, abiJSON []byte,
Expand Down Expand Up @@ -977,12 +1093,6 @@ func (client *Client) GetCollateralInfo(epoch ...*types.Epoch) (info types.Stora
return
}

// /// Return information about total token supply.
// #[rpc(name = "cfx_getCollateralInfo")]
// fn get_collateral_info(
// &self, epoch_number: Option<EpochNumber>,
// ) -> JsonRpcResult<StorageCollateralInfo>;

// =====Debug RPC=====

func (client *Client) GetEpochReceipts(epoch types.EpochOrBlockHash, include_eth_recepits ...bool) (receipts [][]types.TransactionReceipt, err error) {
Expand Down
131 changes: 23 additions & 108 deletions client_test.go
Original file line number Diff line number Diff line change
@@ -1,73 +1,18 @@
package sdk

// GoConvey COMPOSER
// Test NewClient
// Subject: New client use rpc client
// Given a node url and retry params
// When rpc dail error
// Return error
// When rpc dail success
// Return client instance
import (
"context"
"encoding/json"
"fmt"
"os"
"testing"
"time"

. "bou.ke/monkey"
// "github.com/ethereum/go-ethereum/rpc"

"github.com/Conflux-Chain/go-conflux-sdk/types"
"github.com/Conflux-Chain/go-conflux-sdk/types/cfxaddress"
rpc "github.com/openweb3/go-rpc-provider"
"github.com/ethereum/go-ethereum/common"
providers "github.com/openweb3/go-rpc-provider/provider_wrapper"
"github.com/pkg/errors"
. "github.com/smartystreets/goconvey/convey"
"github.com/stretchr/testify/assert"
)

func _TestNewClient(t *testing.T) {

Convey("Subject: New client use rpc client", t, func() {

Convey("Given a node url and retry params", func() {

Convey("When rpc dail error", func() {
//stub for rpc.Dail
guard := Patch(rpc.Dial, func(_ string) (*rpc.Client, error) {
return nil, errors.New("rpc dail fail")
})
defer guard.Unpatch()

client, err := newClientWithOption("", ClientOption{})
Convey("Return error", func() {
So(err, ShouldNotEqual, nil)
So(client, ShouldEqual, nil)
})
})

Convey("When rpc dail success", func() {
//stub for rpc.Dail
guard := Patch(rpc.Dial, func(_ string) (*rpc.Client, error) {
return &rpc.Client{}, nil
})
defer guard.Unpatch()

client, err := newClientWithOption("", ClientOption{})
// fmt.Printf("client:%+v,err:%+v", client, err)

Convey("Return client instance", func() {
So(err, ShouldEqual, nil)
So(client, ShouldNotEqual, nil)
})
})
})
})

}

func TestInterfaceImplementation(t *testing.T) {
var _ ClientOperator = &Client{}
}
Expand Down Expand Up @@ -110,63 +55,33 @@ func callContextMid2(f providers.CallContextFunc) providers.CallContextFunc {
}
}

func _TestEstimateGasAndCollateralAlwaysWithGaspriceNil(t *testing.T) {
c := MustNewClient("https://test.confluxrpc.com", ClientOption{
func TestSendTransaction(t *testing.T) {
client := MustNewClient("http://net8888cfx.confluxrpc.com", ClientOption{
KeystorePath: "./keystore",
Logger: os.Stdout,
})
c.Provider().HookCallContext(func(f providers.CallContextFunc) providers.CallContextFunc {
return func(ctx context.Context, result interface{}, method string, args ...interface{}) error {
if method == "cfx_estimateGasAndCollateral" {
fmt.Printf("cfx_estimateGasAndCollateral args: %+v\n", args)
if args[0].(types.CallRequest).GasPrice != nil {
t.Fatalf("gasPrice should be nil")
}
}
return f(ctx, result, method, args...)
}
client.AccountManager.ImportKey("0x0ccb34a57c54b3e61effebbc3cf3baaf5a03cd07a90836f38d97e08bcd1662f3", "hello")
// assert.NoError(t, err)
client.AccountManager.UnlockDefault("hello")

addr, _ := client.AccountManager.GetDefault()

fmt.Printf("addr %v\n", addr)

txHash, err := client.SendTransaction(types.UnsignedTransaction{
UnsignedTransactionBase: types.UnsignedTransactionBase{
AccessList: types.AccessList{types.AccessTuple{
Address: *addr,
StorageKeys: []common.Hash{
common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"),
},
}},
// Gas: types.NewBigInt(30000),
},
To: addr,
})
c.AccountManager.Create("123456")
defaultAccount, _ := c.AccountManager.GetDefault()
c.EstimateGasAndCollateral(
types.CallRequest{
GasPrice: types.NewBigInt(1000000000),
To: defaultAccount,
})
}

func _TestGetPosTxByNum(t *testing.T) {
c := MustNewClient("https://test-internal.confluxrpc.com", ClientOption{Logger: os.Stdout})
tx, err := c.Pos().GetTransactionByNumber(*types.NewUint64(0x76657))
assert.NoError(t, err)
fmt.Printf("%v\n", tx)
}

func _TestDeposite(t *testing.T) {
c := MustNewClient("https://test.confluxrpc.com", ClientOption{Logger: os.Stdout})
di, err := c.GetDepositList(cfxaddress.MustNew("cfxtest:aanhtnrex2nj56kkbws4yx0jeab34ae16pcap53w13"))
assert.NoError(t, err)
fmt.Printf("%v\n", di)
}

func _TestGetFilterChanges(t *testing.T) {
c := MustNewClient("http://test-internal.confluxrpc.com", ClientOption{Logger: os.Stdout})
filter := c.Filter()
fID, err := filter.NewFilter(types.LogFilter{})
assert.NoError(t, err)

ticker := time.NewTicker(time.Second)
for range ticker.C {
fcg, err := c.Filter().GetFilterChanges(*fID)
assert.NoError(t, err)
j, _ := json.MarshalIndent(fcg, "", " ")
fmt.Printf("new log json: , %s\n", j)
fmt.Printf("new log: %+v\n", fcg)
}
}
fmt.Println(txHash)

func _TestCall(t *testing.T) {
c := MustNewClient("http://net8888cfx.confluxrpc.com", ClientOption{Logger: os.Stdout})
var result interface{}
c.CallRPC(&result, "pos_getEpochState", "0x1234")
}
7 changes: 1 addition & 6 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
module github.com/Conflux-Chain/go-conflux-sdk

go 1.17
go 1.18

require (
bou.ke/monkey v1.0.2
github.com/ethereum/go-ethereum v1.10.15
github.com/mcuadros/go-defaults v1.2.0
github.com/openweb3/go-rpc-provider v0.3.2
Expand All @@ -12,7 +11,6 @@ require (
github.com/pkg/errors v0.9.1
github.com/shopspring/decimal v1.3.1
github.com/sirupsen/logrus v1.9.0
github.com/smartystreets/goconvey v1.6.4
github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4
github.com/stretchr/testify v1.7.0
gopkg.in/urfave/cli.v1 v1.20.0
Expand All @@ -38,7 +36,6 @@ require (
github.com/golang/snappy v0.0.4 // indirect
github.com/google/go-cmp v0.5.7 // indirect
github.com/google/uuid v1.1.5 // indirect
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 // indirect
github.com/gorilla/websocket v1.5.0 // indirect
github.com/graph-gophers/graphql-go v1.3.0 // indirect
github.com/hashicorp/go-bexpr v0.1.10 // indirect
Expand All @@ -50,7 +47,6 @@ require (
github.com/influxdata/influxdb-client-go/v2 v2.4.0 // indirect
github.com/influxdata/line-protocol v0.0.0-20210311194329-9aa0e372d097 // indirect
github.com/jackpal/go-nat-pmp v1.0.2 // indirect
github.com/jtolds/gls v4.20.0+incompatible // indirect
github.com/klauspost/compress v1.14.1 // indirect
github.com/mattn/go-colorable v0.1.8 // indirect
github.com/mattn/go-isatty v0.0.12 // indirect
Expand All @@ -66,7 +62,6 @@ require (
github.com/rjeczalik/notify v0.9.1 // indirect
github.com/rs/cors v1.7.0 // indirect
github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible // indirect
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d // indirect
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 // indirect
github.com/tklauser/go-sysconf v0.3.5 // indirect
github.com/tklauser/numcpus v0.2.2 // indirect
Expand Down
Loading

0 comments on commit 2ced352

Please sign in to comment.