Skip to content

Commit 74cf942

Browse files
ecrecover for transactions (#498)
* ecrecover for transactions * doc update * change tx method to take data, not hash * gen doc
1 parent c05bb83 commit 74cf942

File tree

3 files changed

+58
-18
lines changed

3 files changed

+58
-18
lines changed

cmd/ecrecover/ecrecover.go

Lines changed: 46 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@ import (
77
"math/big"
88
"os"
99

10+
"github.com/0xPolygon/polygon-cli/util"
1011
ethcommon "github.com/ethereum/go-ethereum/common"
1112
"github.com/ethereum/go-ethereum/core/types"
1213
"github.com/ethereum/go-ethereum/ethclient"
1314
ethrpc "github.com/ethereum/go-ethereum/rpc"
14-
"github.com/0xPolygon/polygon-cli/util"
1515
"github.com/rs/zerolog/log"
1616
"github.com/spf13/cobra"
1717
)
@@ -23,9 +23,10 @@ var (
2323
rpcUrl string
2424
blockNumber uint64
2525
filePath string
26+
txData string
2627
)
2728

28-
var EcRecoverCmd = &cobra.Command{
29+
var EcRecoverCmd = &cobra.Command {
2930
Use: "ecrecover",
3031
Short: "Recovers and returns the public key of the signature",
3132
Long: usage,
@@ -35,11 +36,12 @@ var EcRecoverCmd = &cobra.Command{
3536
},
3637
Run: func(cmd *cobra.Command, args []string) {
3738
ctx := cmd.Context()
39+
var (
40+
signerBytes []byte
41+
err error
42+
)
3843

39-
var block *types.Block
40-
var err error
41-
42-
if rpcUrl == "" {
44+
if filePath != "" { // block signer from file
4345
var blockJSON []byte
4446
if filePath != "" {
4547
blockJSON, err = os.ReadFile(filePath)
@@ -61,39 +63,60 @@ var EcRecoverCmd = &cobra.Command{
6163
return
6264
}
6365

64-
block = types.NewBlockWithHeader(&header)
66+
block := types.NewBlockWithHeader(&header)
6567
blockNumber = header.Number.Uint64()
66-
} else {
68+
signerBytes, err = util.Ecrecover(block)
69+
70+
} else if txData != "" { // transaction signer from data
71+
72+
txBytes := ethcommon.FromHex(txData)
73+
var tx types.Transaction
74+
err = tx.UnmarshalBinary(txBytes)
75+
if err != nil {
76+
log.Error().Err(err).Msg("Unable to decode transaction")
77+
return
78+
}
79+
signerBytes, err = util.EcrecoverTx(&tx)
80+
if err != nil {
81+
log.Error().Err(err).Msg("Unable to retrieve block")
82+
return
83+
}
84+
85+
} else { // block signer block-number, requires rcp-url
86+
if rpcUrl == "" {
87+
log.Error().Msg("No RPC URL provided")
88+
return
89+
}
6790
var rpc *ethrpc.Client
6891
rpc, err = ethrpc.DialContext(ctx, rpcUrl)
6992
if err != nil {
7093
log.Error().Err(err).Msg("Unable to dial rpc")
7194
return
7295
}
73-
7496
ec := ethclient.NewClient(rpc)
97+
defer ec.Close()
7598

99+
var block *types.Block
76100
if blockNumber == 0 {
77101
blockNumber, err = ec.BlockNumber(ctx)
78102
if err != nil {
79103
log.Error().Err(err).Msg("Unable to retrieve latest block number")
80104
return
81105
}
106+
cmd.Println("Using latest block number:", blockNumber)
82107
}
83-
84108
block, err = ec.BlockByNumber(ctx, big.NewInt(int64(blockNumber)))
85109
if err != nil {
86110
log.Error().Err(err).Msg("Unable to retrieve block")
87111
return
88112
}
113+
signerBytes, err = util.Ecrecover(block)
89114
}
90115

91-
signerBytes, err := util.Ecrecover(block)
92116
if err != nil {
93117
log.Error().Err(err).Msg("Unable to recover signature")
94118
return
95119
}
96-
cmd.Printf("Recovering signer from block #%d\n", blockNumber)
97120
cmd.Println(ethcommon.BytesToAddress(signerBytes))
98121
},
99122
}
@@ -102,12 +125,18 @@ func init() {
102125
EcRecoverCmd.PersistentFlags().StringVarP(&rpcUrl, "rpc-url", "r", "", "The RPC endpoint url")
103126
EcRecoverCmd.PersistentFlags().Uint64VarP(&blockNumber, "block-number", "b", 0, "Block number to check the extra data for (default: latest)")
104127
EcRecoverCmd.PersistentFlags().StringVarP(&filePath, "file", "f", "", "Path to a file containing block information in JSON format")
128+
EcRecoverCmd.PersistentFlags().StringVarP(&txData, "tx", "t", "", "Transaction data in hex format")
129+
130+
// The sources of decoding are mutually exclusive
131+
EcRecoverCmd.MarkFlagsMutuallyExclusive("file", "block-number", "tx")
105132
}
106133

107-
func checkFlags() (err error) {
108-
if rpcUrl != "" && util.ValidateUrl(rpcUrl) != nil {
109-
return
134+
func checkFlags() error {
135+
var err error
136+
if rpcUrl != "" {
137+
if err = util.ValidateUrl(rpcUrl); err != nil {
138+
return err
139+
}
110140
}
111-
112-
return nil
141+
return err
113142
}

doc/polycli_ecrecover.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ JSON Data passed in follows object definition [here](https://www.quicknode.com/d
4848
-f, --file string Path to a file containing block information in JSON format
4949
-h, --help help for ecrecover
5050
-r, --rpc-url string The RPC endpoint url
51+
-t, --tx string Transaction data in hex format
5152
```
5253

5354
The command also inherits flags from parent commands.

util/util.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@ import (
44
"context"
55
"encoding/json"
66
"fmt"
7+
"reflect"
78
"strconv"
89
"strings"
910
"time"
10-
"reflect"
1111

1212
"github.com/cenkalti/backoff"
1313
"github.com/ethereum/go-ethereum/common/hexutil"
@@ -50,6 +50,16 @@ func Ecrecover(block *types.Block) ([]byte, error) {
5050
return signer, nil
5151
}
5252

53+
func EcrecoverTx(tx *types.Transaction) ([]byte, error) {
54+
chainID := tx.ChainId()
55+
signer := types.LatestSignerForChainID(chainID)
56+
from, err := types.Sender(signer, tx)
57+
if err != nil {
58+
return nil, err
59+
}
60+
return from.Bytes(), nil
61+
}
62+
5363
func GetBlockRange(ctx context.Context, from, to uint64, c *ethrpc.Client) ([]*json.RawMessage, error) {
5464
blms := make([]ethrpc.BatchElem, 0)
5565
for i := from; i <= to; i = i + 1 {

0 commit comments

Comments
 (0)