Skip to content

Commit

Permalink
module: double indirection (#178)
Browse files Browse the repository at this point in the history
* updated factory and `rpctest`

* module: updated to new API

* use double indirection

* examples: fix

* drop deps check of `examples/`

* updated doc

* fixed `<br/>

* added `web3` section

---------

Co-authored-by: lmittmann <[email protected]>
  • Loading branch information
lmittmann and lmittmann committed Aug 22, 2024
1 parent 1a5b458 commit f2f9118
Show file tree
Hide file tree
Showing 38 changed files with 233 additions and 343 deletions.
4 changes: 0 additions & 4 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,6 @@ updates:
directory: "/"
schedule:
interval: "daily"
- package-ecosystem: "gomod"
directory: "/examples"
schedule:
interval: "daily"
- package-ecosystem: "npm"
directory: "/docs"
schedule:
Expand Down
38 changes: 19 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ defer client.Close()

// 2. Make a batch request
var (
balance big.Int
balance *big.Int
nonce uint64
)
if err := client.Call(
Expand Down Expand Up @@ -168,47 +168,47 @@ List of supported RPC methods for [`w3.Client`](https://pkg.go.dev/github.com/lm

| Method | Go Code
| :---------------------------------------- | :-------
| `eth_blockNumber` | `eth.BlockNumber().Returns(blockNumber *big.Int)`
| `eth_blockNumber` | `eth.BlockNumber().Returns(blockNumber **big.Int)`
| `eth_call` | `eth.Call(msg *w3types.Message, blockNumber *big.Int, overrides w3types.State).Returns(output *[]byte)`<br>`eth.CallFunc(contract common.Address, f w3types.Func, args ...any).Returns(returns ...any)`
| `eth_chainId` | `eth.ChainID().Returns(chainID *uint64)`
| `eth_createAccessList` | `eth.AccessList(msg *w3types.Message, blockNumber *big.Int).Returns(resp *eth.AccessListResponse)`
| `eth_createAccessList` | `eth.AccessList(msg *w3types.Message, blockNumber *big.Int).Returns(resp **eth.AccessListResponse)`
| `eth_estimateGas` | `eth.EstimateGas(msg *w3types.Message, blockNumber *big.Int).Returns(gas *uint64)`
| `eth_gasPrice` | `eth.GasPrice().Returns(gasPrice *big.Int)`
| `eth_maxPriorityFeePerGas` | `eth.GasTipCap().Returns(gasTipCap *big.Int)`
| `eth_getBalance` | `eth.Balance(addr common.Address, blockNumber *big.Int).Returns(balance *big.Int)`
| `eth_getBlockByHash` | `eth.BlockByHash(hash common.Hash).Returns(block *types.Block)`<br>`eth.HeaderByHash(hash common.Hash).Returns(header *types.Header)`
| `eth_getBlockByNumber` | `eth.BlockByNumber(number *big.Int).Returns(block *types.Block)`<br>`eth.HeaderByNumber(number *big.Int).Returns(header *types.Header)`
| `eth_gasPrice` | `eth.GasPrice().Returns(gasPrice **big.Int)`
| `eth_maxPriorityFeePerGas` | `eth.GasTipCap().Returns(gasTipCap **big.Int)`
| `eth_getBalance` | `eth.Balance(addr common.Address, blockNumber *big.Int).Returns(balance **big.Int)`
| `eth_getBlockByHash` | `eth.BlockByHash(hash common.Hash).Returns(block *types.Block)`<br>`eth.HeaderByHash(hash common.Hash).Returns(header **types.Header)`
| `eth_getBlockByNumber` | `eth.BlockByNumber(number *big.Int).Returns(block *types.Block)`<br>`eth.HeaderByNumber(number *big.Int).Returns(header **types.Header)`
| `eth_getBlockReceipts` | `eth.BlockReceipts(blockNumber *big.Int).Returns(receipts *types.Receipts)`
| `eth_getBlockTransactionCountByHash` | `eth.BlockTxCountByHash(hash common.Hash).Returns(count *uint)`
| `eth_getBlockTransactionCountByNumber` | `eth.BlockTxCountByNumber(number *big.Int).Returns(count *uint)`
| `eth_getCode` | `eth.Code(addr common.Address, blockNumber *big.Int).Returns(code *[]byte)`
| `eth_getLogs` | `eth.Logs(q ethereum.FilterQuery).Returns(logs *[]types.Log)`
| `eth_getStorageAt` | `eth.StorageAt(addr common.Address, slot common.Hash, blockNumber *big.Int).Returns(storage *common.Hash)`
| `eth_getTransactionByHash` | `eth.Tx(hash common.Hash).Returns(tx *types.Transaction)`
| `eth_getTransactionByBlockHashAndIndex` | `eth.TxByBlockHashAndIndex(blockHash common.Hash, index uint).Returns(tx *types.Transaction)`
| `eth_getTransactionByBlockNumberAndIndex` | `eth.TxByBlockNumberAndIndex(blockNumber *big.Int, index uint).Returns(tx *types.Transaction)`
| `eth_getTransactionByHash` | `eth.Tx(hash common.Hash).Returns(tx **types.Transaction)`
| `eth_getTransactionByBlockHashAndIndex` | `eth.TxByBlockHashAndIndex(blockHash common.Hash, index uint).Returns(tx **types.Transaction)`
| `eth_getTransactionByBlockNumberAndIndex` | `eth.TxByBlockNumberAndIndex(blockNumber *big.Int, index uint).Returns(tx **types.Transaction)`
| `eth_getTransactionCount` | `eth.Nonce(addr common.Address, blockNumber *big.Int).Returns(nonce *uint)`
| `eth_getTransactionReceipt` | `eth.TxReceipt(txHash common.Hash).Returns(receipt *types.Receipt)`
| `eth_getTransactionReceipt` | `eth.TxReceipt(txHash common.Hash).Returns(receipt **types.Receipt)`
| `eth_sendRawTransaction` | `eth.SendRawTx(rawTx []byte).Returns(hash *common.Hash)`<br>`eth.SendTx(tx *types.Transaction).Returns(hash *common.Hash)`
| `eth_getUncleByBlockHashAndIndex` | `eth.UncleByBlockHashAndIndex(hash common.Hash, index uint).Returns(uncle *types.Header)`
| `eth_getUncleByBlockNumberAndIndex` | `eth.UncleByBlockNumberAndIndex(number *big.Int, index uint).Returns(uncle *types.Header)`
| `eth_getUncleByBlockHashAndIndex` | `eth.UncleByBlockHashAndIndex(hash common.Hash, index uint).Returns(uncle **types.Header)`
| `eth_getUncleByBlockNumberAndIndex` | `eth.UncleByBlockNumberAndIndex(number *big.Int, index uint).Returns(uncle **types.Header)`
| `eth_getUncleCountByBlockHash` | `eth.UncleCountByBlockHash(hash common.Hash).Returns(count *uint)`
| `eth_getUncleCountByBlockNumber` | `eth.UncleCountByBlockNumber(number *big.Int).Returns(count *uint)`

### [`debug`](https://pkg.go.dev/github.com/lmittmann/w3/module/debug)

| Method | Go Code
| :----------------------- | :-------
| `debug_traceCall` | `debug.TraceCall(msg *w3types.Message, blockNumber *big.Int, config *debug.TraceConfig).Returns(trace *debug.Trace)`<br>`debug.CallTraceCall(msg *w3types.Message, blockNumber *big.Int, overrides w3types.State).Returns(trace *debug.CallTrace)`
| `debug_traceTransaction` | `debug.TraceTx(txHash common.Hash, config *debug.TraceConfig).Returns(trace *debug.Trace)`<br>`debug.CallTraceTx(txHash common.Hash, overrides w3types.State).Returns(trace *debug.CallTrace)`
| `debug_traceCall` | `debug.TraceCall(msg *w3types.Message, blockNumber *big.Int, config *debug.TraceConfig).Returns(trace **debug.Trace)`<br>`debug.CallTraceCall(msg *w3types.Message, blockNumber *big.Int, overrides w3types.State).Returns(trace **debug.CallTrace)`
| `debug_traceTransaction` | `debug.TraceTx(txHash common.Hash, config *debug.TraceConfig).Returns(trace **debug.Trace)`<br>`debug.CallTraceTx(txHash common.Hash, overrides w3types.State).Returns(trace **debug.CallTrace)`

### [`txpool`](https://pkg.go.dev/github.com/lmittmann/w3/module/txpool)

| Method | Go Code
| :--------------------| :-------
| `txpool_content` | `txpool.Content().Returns(resp *txpool.ContentResponse)`
| `txpool_contentFrom` | `txpool.ContentFrom(addr common.Address).Returns(resp *txpool.ContentFromResponse)`
| `txpool_status` | `txpool.Status().Returns(resp *txpool.StatusResponse)`
| `txpool_content` | `txpool.Content().Returns(resp **txpool.ContentResponse)`
| `txpool_contentFrom` | `txpool.ContentFrom(addr common.Address).Returns(resp **txpool.ContentFromResponse)`
| `txpool_status` | `txpool.Status().Returns(resp **txpool.StatusResponse)`

### [`web3`](https://pkg.go.dev/github.com/lmittmann/w3/module/web3)

Expand Down
35 changes: 10 additions & 25 deletions client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ func ExampleClient() {

// 2. Make a batch request
var (
balance big.Int
balance *big.Int
nonce uint64
)
if err := client.Call(
Expand All @@ -58,7 +58,7 @@ func ExampleClient() {
// handle error
}

fmt.Printf("balance: %s\nnonce: %d\n", w3.FromWei(&balance, 18), nonce)
fmt.Printf("balance: %s\nnonce: %d\n", w3.FromWei(balance, 18), nonce)
}

func ExampleClient_Call_balanceOf() {
Expand All @@ -76,8 +76,8 @@ func ExampleClient_Call_balanceOf() {
balanceOf = w3.MustNewFunc("balanceOf(address)", "uint256")

// Declare variables for the RPC responses.
ethBalance big.Int
weth9Balance big.Int
ethBalance *big.Int
weth9Balance *big.Int
)

// Do batch request (both RPC requests are send in the same
Expand All @@ -91,7 +91,7 @@ func ExampleClient_Call_balanceOf() {
}

fmt.Printf("Combined balance: %v wei",
new(big.Int).Add(&ethBalance, &weth9Balance),
new(big.Int).Add(ethBalance, weth9Balance),
)
}

Expand All @@ -103,7 +103,7 @@ func ExampleClient_Call_nonceAndBalance() {
addr = w3.A("0x000000000000000000000000000000000000c0Fe")

nonce uint64
balance big.Int
balance *big.Int
)

if err := client.Call(
Expand All @@ -114,7 +114,7 @@ func ExampleClient_Call_nonceAndBalance() {
return
}

fmt.Printf("%s: Nonce: %d, Balance: ♦%s\n", addr, nonce, w3.FromWei(&balance, 18))
fmt.Printf("%s: Nonce: %d, Balance: ♦%s\n", addr, nonce, w3.FromWei(balance, 18))
}

func ExampleClient_Call_sendERC20transferTx() {
Expand Down Expand Up @@ -329,21 +329,6 @@ func (c *testCaller) HandleResponse(elem rpc.BatchElem) (err error) {
return c.ReturnErr
}

func TestClientCall_NilReference(t *testing.T) {
client := w3.MustDial("https://rpc.ankr.com/eth")
defer client.Close()

var block *types.Block
err := client.Call(
eth.BlockByNumber(nil).Returns(block),
)

want := "w3: cannot return Go value of type *types.Block: value must be passed as a non-nil pointer reference"
if diff := cmp.Diff(want, err.Error()); diff != "" {
t.Fatalf("(-want, +got)\n%s", diff)
}
}

func BenchmarkCall_BalanceNonce(b *testing.B) {
if *benchRPC == "" {
b.Skipf("Missing -benchRPC")
Expand All @@ -360,7 +345,7 @@ func BenchmarkCall_BalanceNonce(b *testing.B) {
b.Run("Batch", func(b *testing.B) {
var (
nonce uint64
balance big.Int
balance *big.Int
)
for range b.N {
w3Client.Call(
Expand Down Expand Up @@ -395,7 +380,7 @@ func BenchmarkCall_Balance100(b *testing.B) {
}

b.Run("Batch", func(b *testing.B) {
var balance big.Int
var balance *big.Int
for range b.N {
requests := make([]w3types.RPCCaller, len(addr100))
for j := range len(requests) {
Expand Down Expand Up @@ -477,7 +462,7 @@ func BenchmarkCall_Block100(b *testing.B) {
}

b.Run("Batch", func(b *testing.B) {
var block types.Block
var block *types.Block
for range b.N {
requests := make([]w3types.RPCCaller, len(block100))
for j := range len(requests) {
Expand Down
38 changes: 19 additions & 19 deletions docs/pages/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ defer client.Close()

// 2. Make a batch request
var (
balance big.Int
balance *big.Int
nonce uint64
)
if err := client.Call(
Expand Down Expand Up @@ -188,47 +188,47 @@ List of supported RPC methods for [`w3.Client`](https://pkg.go.dev/github.com/lm

| Method | Go Code
| :---------------------------------------- | :-------
| `eth_blockNumber` | `eth.BlockNumber().Returns(blockNumber *big.Int)`
| `eth_blockNumber` | `eth.BlockNumber().Returns(blockNumber **big.Int)`
| `eth_call` | `eth.Call(msg *w3types.Message, blockNumber *big.Int, overrides w3types.State).Returns(output *[]byte)`<br/>`eth.CallFunc(contract common.Address, f w3types.Func, args ...any).Returns(returns ...any)`
| `eth_chainId` | `eth.ChainID().Returns(chainID *uint64)`
| `eth_createAccessList` | `eth.AccessList(msg *w3types.Message, blockNumber *big.Int).Returns(resp *eth.AccessListResponse)`
| `eth_createAccessList` | `eth.AccessList(msg *w3types.Message, blockNumber *big.Int).Returns(resp **eth.AccessListResponse)`
| `eth_estimateGas` | `eth.EstimateGas(msg *w3types.Message, blockNumber *big.Int).Returns(gas *uint64)`
| `eth_gasPrice` | `eth.GasPrice().Returns(gasPrice *big.Int)`
| `eth_maxPriorityFeePerGas` | `eth.GasTipCap().Returns(gasTipCap *big.Int)`
| `eth_getBalance` | `eth.Balance(addr common.Address, blockNumber *big.Int).Returns(balance *big.Int)`
| `eth_getBlockByHash` | `eth.BlockByHash(hash common.Hash).Returns(block *types.Block)`<br/>`eth.HeaderByHash(hash common.Hash).Returns(header *types.Header)`
| `eth_getBlockByNumber` | `eth.BlockByNumber(number *big.Int).Returns(block *types.Block)`<br/>`eth.HeaderByNumber(number *big.Int).Returns(header *types.Header)`
| `eth_gasPrice` | `eth.GasPrice().Returns(gasPrice **big.Int)`
| `eth_maxPriorityFeePerGas` | `eth.GasTipCap().Returns(gasTipCap **big.Int)`
| `eth_getBalance` | `eth.Balance(addr common.Address, blockNumber *big.Int).Returns(balance **big.Int)`
| `eth_getBlockByHash` | `eth.BlockByHash(hash common.Hash).Returns(block *types.Block)`<br/>`eth.HeaderByHash(hash common.Hash).Returns(header **types.Header)`
| `eth_getBlockByNumber` | `eth.BlockByNumber(number *big.Int).Returns(block *types.Block)`<br/>`eth.HeaderByNumber(number *big.Int).Returns(header **types.Header)`
| `eth_getBlockReceipts` | `eth.BlockReceipts(blockNumber *big.Int).Returns(receipts *types.Receipts)`
| `eth_getBlockTransactionCountByHash` | `eth.BlockTxCountByHash(hash common.Hash).Returns(count *uint)`
| `eth_getBlockTransactionCountByNumber` | `eth.BlockTxCountByNumber(number *big.Int).Returns(count *uint)`
| `eth_getCode` | `eth.Code(addr common.Address, blockNumber *big.Int).Returns(code *[]byte)`
| `eth_getLogs` | `eth.Logs(q ethereum.FilterQuery).Returns(logs *[]types.Log)`
| `eth_getStorageAt` | `eth.StorageAt(addr common.Address, slot common.Hash, blockNumber *big.Int).Returns(storage *common.Hash)`
| `eth_getTransactionByHash` | `eth.Tx(hash common.Hash).Returns(tx *types.Transaction)`
| `eth_getTransactionByBlockHashAndIndex` | `eth.TxByBlockHashAndIndex(blockHash common.Hash, index uint).Returns(tx *types.Transaction)`
| `eth_getTransactionByBlockNumberAndIndex` | `eth.TxByBlockNumberAndIndex(blockNumber *big.Int, index uint).Returns(tx *types.Transaction)`
| `eth_getTransactionByHash` | `eth.Tx(hash common.Hash).Returns(tx **types.Transaction)`
| `eth_getTransactionByBlockHashAndIndex` | `eth.TxByBlockHashAndIndex(blockHash common.Hash, index uint).Returns(tx **types.Transaction)`
| `eth_getTransactionByBlockNumberAndIndex` | `eth.TxByBlockNumberAndIndex(blockNumber *big.Int, index uint).Returns(tx **types.Transaction)`
| `eth_getTransactionCount` | `eth.Nonce(addr common.Address, blockNumber *big.Int).Returns(nonce *uint)`
| `eth_getTransactionReceipt` | `eth.TxReceipt(txHash common.Hash).Returns(receipt *types.Receipt)`
| `eth_getTransactionReceipt` | `eth.TxReceipt(txHash common.Hash).Returns(receipt **types.Receipt)`
| `eth_sendRawTransaction` | `eth.SendRawTx(rawTx []byte).Returns(hash *common.Hash)`<br/>`eth.SendTx(tx *types.Transaction).Returns(hash *common.Hash)`
| `eth_getUncleByBlockHashAndIndex` | `eth.UncleByBlockHashAndIndex(hash common.Hash, index uint).Returns(uncle *types.Header)`
| `eth_getUncleByBlockNumberAndIndex` | `eth.UncleByBlockNumberAndIndex(number *big.Int, index uint).Returns(uncle *types.Header)`
| `eth_getUncleByBlockHashAndIndex` | `eth.UncleByBlockHashAndIndex(hash common.Hash, index uint).Returns(uncle **types.Header)`
| `eth_getUncleByBlockNumberAndIndex` | `eth.UncleByBlockNumberAndIndex(number *big.Int, index uint).Returns(uncle **types.Header)`
| `eth_getUncleCountByBlockHash` | `eth.UncleCountByBlockHash(hash common.Hash).Returns(count *uint)`
| `eth_getUncleCountByBlockNumber` | `eth.UncleCountByBlockNumber(number *big.Int).Returns(count *uint)`

### [`debug`](https://pkg.go.dev/github.com/lmittmann/w3/module/debug)

| Method | Go Code
| :----------------------- | :-------
| `debug_traceCall` | `debug.TraceCall(msg *w3types.Message, blockNumber *big.Int, config *debug.TraceConfig).Returns(trace *debug.Trace)`<br/>`debug.CallTraceCall(msg *w3types.Message, blockNumber *big.Int, overrides w3types.State).Returns(trace *debug.CallTrace)`
| `debug_traceTransaction` | `debug.TraceTx(txHash common.Hash, config *debug.TraceConfig).Returns(trace *debug.Trace)`<br/>`debug.CallTraceTx(txHash common.Hash, overrides w3types.State).Returns(trace *debug.CallTrace)`
| `debug_traceCall` | `debug.TraceCall(msg *w3types.Message, blockNumber *big.Int, config *debug.TraceConfig).Returns(trace **debug.Trace)`<br/>`debug.CallTraceCall(msg *w3types.Message, blockNumber *big.Int, overrides w3types.State).Returns(trace **debug.CallTrace)`
| `debug_traceTransaction` | `debug.TraceTx(txHash common.Hash, config *debug.TraceConfig).Returns(trace **debug.Trace)`<br/>`debug.CallTraceTx(txHash common.Hash, overrides w3types.State).Returns(trace **debug.CallTrace)`

### [`txpool`](https://pkg.go.dev/github.com/lmittmann/w3/module/txpool)

| Method | Go Code
| :--------------------| :-------
| `txpool_content` | `txpool.Content().Returns(resp *txpool.ContentResponse)`
| `txpool_contentFrom` | `txpool.ContentFrom(addr common.Address).Returns(resp *txpool.ContentFromResponse)`
| `txpool_status` | `txpool.Status().Returns(resp *txpool.StatusResponse)`
| `txpool_content` | `txpool.Content().Returns(resp **txpool.ContentResponse)`
| `txpool_contentFrom` | `txpool.ContentFrom(addr common.Address).Returns(resp **txpool.ContentFromResponse)`
| `txpool_status` | `txpool.Status().Returns(resp **txpool.StatusResponse)`

### [`web3`](https://pkg.go.dev/github.com/lmittmann/w3/module/web3)

Expand Down
8 changes: 4 additions & 4 deletions examples/scan_blocks/main.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
scan_blocks interates over blocks with their transactions from a given start block.
scan_blocks iterates over blocks with their transactions from a given start block.
Usage:
Expand Down Expand Up @@ -37,7 +37,7 @@ func main() {
// parse flags
flag.Uint64Var(&startBlock, "start", 10_000_000, "Start block")
flag.Usage = func() {
fmt.Println("scan_blocks interates over blocks with their transactions from a given start block.")
fmt.Println("scan_blocks iterates over blocks with their transactions from a given start block.")
flag.PrintDefaults()
}
flag.Parse()
Expand All @@ -48,7 +48,7 @@ func main() {

// fetch blocks in bulk
calls := make([]w3types.RPCCaller, bulkSize)
blocks := make([]types.Block, bulkSize)
blocks := make([]*types.Block, bulkSize)

for i, txCount := 0, 0; ; i++ {
j := i % bulkSize
Expand All @@ -62,7 +62,7 @@ func main() {

for _, block := range blocks {
txCount += len(block.Transactions())
processBlock(&block)
processBlock(block)
}
fmt.Printf("\rFetched %d blocks with a total of %d transactions", i+1, txCount)
}
Expand Down
13 changes: 7 additions & 6 deletions internal/module/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,10 @@ func WithRetWrapper[T any](fn RetWrapperFunc[T]) Option[T] {
}
}

var (
HexBigRetWrapper RetWrapperFunc[big.Int] = func(ret *big.Int) any { return (*hexutil.Big)(ret) }
HexUintRetWrapper RetWrapperFunc[uint] = func(ret *uint) any { return (*hexutil.Uint)(ret) }
HexUint64RetWrapper RetWrapperFunc[uint64] = func(ret *uint64) any { return (*hexutil.Uint64)(ret) }
HexBytesRetWrapper RetWrapperFunc[[]byte] = func(ret *[]byte) any { return (*hexutil.Bytes)(ret) }
)
func HexBigRetWrapper(ret **big.Int) any {
*ret = new(big.Int)
return (*hexutil.Big)(*ret)
}
func HexUintRetWrapper(ret *uint) any { return (*hexutil.Uint)(ret) }
func HexUint64RetWrapper(ret *uint64) any { return (*hexutil.Uint64)(ret) }
func HexBytesRetWrapper(ret *[]byte) any { return (*hexutil.Bytes)(ret) }
Loading

0 comments on commit f2f9118

Please sign in to comment.