How can I decode a raw transaction using Go / go-ethereum ? There is no method/function to read the raw bytes or the hex into a transaction https://godoc.org/github.com/ethereum/go-ethereum/core/types . Basically I just want to extract the destination address and the amount sent.
-
Possible duplicate of How can I easily parse a raw transaction?– Ajoy BhatiaCommented Jan 24, 2018 at 17:05
-
I voted to close this as a duplicate of ethereum.stackexchange.com/questions/4196/…. If you think it is not a duplicate or are for some reason not satisfied with the answers to that question, please edit question explaining why it should be reopened.– Ajoy BhatiaCommented Jan 24, 2018 at 17:07
-
@AjoyBhatia This question seems to specifically be about how to do this using go-ethereum.– user19510Commented Jan 24, 2018 at 19:20
-
@smarx - That is correct. I retracted my Close vote– Ajoy BhatiaCommented Jan 24, 2018 at 19:48
4 Answers
Using the official go-ethereum package:
import (
"encoding/hex"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/rlp"
)
func GetToAddressFromRawTransaction(rawTxHex string) (*common.Address, error) {
rawTxData, err := hex.DecodeString(rawTxHex[2:]) // Remove hex prefix "0x..."
if err != nil {
return nil, err
}
var tx types.Transaction
err = rlp.DecodeBytes(rawTxData, &tx)
if err != nil {
return nil, err
}
return tx.To(), nil
}
Look at the methods of the Transaction
type to access data in the tx object.
Here's a working code on github
-
may I ask what are you doing in that loop to decode the public key ??? What are the sig1 and sig2 and why do you need a public key at all?– NulikCommented Jun 21, 2018 at 2:32
-
@Nulik For normal using of blockchain you don't need a public key. But if you want to research or to know deeper about EC cryptography you might be eager to find a public key. In my code sig1 and sig2 is a signature of the message. It consists of R+S+V (learn more about elliptic curves). R and S are known. V can be 00 or 01, so we just check both options.– TarikCommented Jun 22, 2018 at 10:47
With introduction of EIP-1559, rlp.DecodeBytes(..)
no longer works and you'd have to use tx.UnmarshalBinary(..)
instead. Here's an example:
package main
import (
"github.com/davecgh/go-spew/spew"
)
func deraw() {
// eip-1559 tx: 0xc2163f50770bd4bfd3c13848b405a56a451ae2a39cfa5a236ea2738ce44aa9df
rawTx := "02f8740181bf8459682f00851191460ee38252089497e542ec6b81dea28f212775ce8ac436ab77a7df880de0b6b3a764000080c080a02bc11202cee115fe22558ce2edb25c621266ce75f75e9b10da9a2ae72460ad4ea07d573eef31fdebf0f5f93eb7721924a082907419eb97a8dda0dd20a4a5b954a1"
// legacy tx
//rawTx := "f86d8202b28477359400825208944592d8f8d7b001e72cb26a73e4fa1806a51ac79d880de0b6b3a7640000802ca05924bde7ef10aa88db9c66dd4f5fb16b46dff2319b9968be983118b57bb50562a001b24b31010004f13d9a26b320845257a6cfc2bf819a3d55e3fc86263c5f0772"
tx := &types.Transaction{}
rawTxBytes, err := hex.DecodeString(rawTx)
if err != nil {
fmt.Println("err:", err)
return 1
}
err = tx.UnmarshalBinary(rawTxBytes)
if err != nil {
fmt.Println("err:", err)
return 1
}
spew.Dump(tx)
}
Alternatively, you can extract what you want using rlpdump
.
-
This should be the top answer! huge thx, been bugging me for days– gabkovCommented Jan 25 at 15:56
Here is a package I found out about from this answer:
https://github.com/ConsenSys/abi-decoder
See the code block titled Decode Tx data. I think this should do what you want.
-
Can you understand the difference between javascript and Go ?– BooksCommented Jan 24, 2018 at 20:17
-
Ok. Ok. I should read questions more carefully. go-ethereum also has a Javascript API to communicate with the node using IPC or RPC. That is what I have always used because I programmed in Javascript. Perhaps, when you said Go / go-ethereum, you meant an application in Go (i.e. not Javascript) interacting with the go-ethereum client? Commented Jan 24, 2018 at 20:32
Here's a full example of how to read transaction values (ie, from address, eth value, etc..) in Go.
package main
import (
"context"
"fmt"
"log"
"math/big"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethclient"
)
func main() {
client, err := ethclient.Dial("https://mainnet.infura.io")
if err != nil {
log.Fatal(err)
}
blockNumber := big.NewInt(5671744)
block, err := client.BlockByNumber(context.Background(), blockNumber)
if err != nil {
log.Fatal(err)
}
for _, tx := range block.Transactions() {
fmt.Println(tx.Hash().Hex()) // 0x5d49fcaa394c97ec8a9c3e7bd9e8388d420fb050a52083ca52ff24b3b65bc9c2
fmt.Println(tx.Value().String()) // 10000000000000000
fmt.Println(tx.Gas()) // 105000
fmt.Println(tx.GasPrice().Uint64()) // 102000000000
fmt.Println(tx.Nonce()) // 110644
fmt.Println(tx.Data()) // []
fmt.Println(tx.To().Hex()) // 0x55fE59D8Ad77035154dDd0AD0388D09Dd4047A8e
if msg, err := tx.AsMessage(types.HomesteadSigner{}); err != nil {
fmt.Println(msg.From().Hex()) // 0x0fD081e3Bb178dc45c0cb23202069ddA57064258
}
receipt, err := client.TransactionReceipt(context.Background(), tx.Hash())
if err != nil {
log.Fatal(err)
}
fmt.Println(receipt.Status) // 1
}
}
If you have the raw tx hex, here's how you can decode it into a tx type:
package main
import (
"encoding/hex"
"log"
"github.com/c3systems/vendor.bak/github.com/davecgh/go-spew/spew"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/rlp"
)
func main() {
client, err := ethclient.Dial("https://rinkeby.infura.io")
if err != nil {
log.Fatal(err)
}
rawTx := "f86d8202b28477359400825208944592d8f8d7b001e72cb26a73e4fa1806a51ac79d880de0b6b3a7640000802ca05924bde7ef10aa88db9c66dd4f5fb16b46dff2319b9968be983118b57bb50562a001b24b31010004f13d9a26b320845257a6cfc2bf819a3d55e3fc86263c5f0772"
var tx *types.Transaction
rawTxBytes, err := hex.DecodeString(rawTx)
rlp.DecodeBytes(rawTxBytes, &tx)
spew.Dump(tx)
}