Necesito firmar una transacción fuera de línea en golang. Tengo lo siguiente, que es una ligera modificación de esta respuesta a una pregunta similar:
import "github.com/ethereum/go-ethereum/core/types"
import "github.com/ethereum/go-ethereum/common"
import "github.com/ethereum/go-ethereum/crypto"
type GethTxn struct {
To string `json:"to"`
From string `json:"from"`
Gas string `json:"gas"`
GasPrice string `json:"gasPrice"`
Value string `json:"value"`
Data string `json:"input"`
}
func SignTxn(from string, _to string, data []byte, nonce uint64, value int64, gas *big.Int, gasPrice *big.Int, privkey *ecdsa.PrivateKey) (*GethTxn, error) {
var parsed_tx = new(GethTxn)
var amount = big.NewInt(value)
var bytesto [20]byte
_bytesto, _ := hex.DecodeString(_to[2:])
copy(bytesto[:], _bytesto)
to := common.Address([20]byte(bytesto))
signer := types.NewEIP155Signer(nil)
tx := types.NewTransaction(nonce, to, amount, gas, gasPrice, data)
signature, _ := crypto.Sign(tx.SigHash(signer).Bytes(), privkey)
signed_tx, _ := tx.WithSignature(signer, signature)
json_tx, _ := signed_tx.MarshalJSON()
_ = json.Unmarshal(json_tx, parsed_tx)
parsed_tx.From = from
fmt.Println("data", parsed_tx.Data)
return parsed_tx, nil
}
Lo que quiero es la carga útil de la transacción sin procesar, pero lo que obtengo es incorrecto. Creo que quiero parsed_data.Data
, pero no estoy seguro. Lo que estoy buscando es un Go análogo a la siguiente función JS:
var Tx = require('ethereumjs-tx');
var privateKey = new Buffer(pkey, 'hex')
var tx = new Tx(txn);
tx.sign(privateKey);
var serializedTx = tx.serialize().toString('hex')
¿Dónde serializedTx
está una cadena (la carga útil que quiero).
Soy un novato de Golang, así que sospecho que solo estoy haciendo un mal uso de geth, pero cualquier ayuda sería muy apreciada. He dedicado bastante tiempo a este problema.
Puede usar dos métodos para obtener el RLP de transacción sin procesar
Obtenga el String()
de la transacción firmada. Puede invocarlo directamente o dejar que la fmt
biblioteca lo haga por usted:
my_string_var = signed_tx.String()
o
my_string_var = fmt.Sprintf("%v", signed_tx)
El problema es que necesitará analizar la salida, que será algo así como
TX(57c9544749f223acdff0be77876a4a45125cef360530caa97a92c359e4d7a6ce)
Contract: false
From: 1600da1bcbef5599e09532f230ced99db0619b95
To: 1737b4e8e4101334b1b1965d3d739c41cc54f096
Nonce: 0
GasPrice: 0x1bc16d674ec80000
GasLimit 0x186a0
Value: 0x0
Data: 0xdeaa59df000000000000000000000000cbfdfb9fb838b9090a7fe1976ed98017632b44f1
V: 0x78
R: 0xa484a59015d08e736f59edf07ffb32f73151fddec52885b1f29cbcfd7aac203
S: 0x842a3a63c2fb1771cd0495b93a4db94692d4733baa9e96c559ddc4ff600422
Hex: f88b80881bc16d674ec80000830186a0941737b4e8e4101334b1b1965d3d739c41cc54f09680a4deaa59df000000000000000000000000cbfdfb9fb838b9090a7fe1976ed98017632b44f178a00a484a59015d08e736f59edf07ffb32f73151fddec52885b1f29cbcfd7aac2039f842a3a63c2fb1771cd0495b93a4db94692d4733baa9e96c559ddc4ff600422
Use el método GetRlp()
de la estructura Transactions
(plural, con una s) en su lugar
Creamos una variable ts
y la rellenamos con esta transacción firmada
ts := types.Transactions{signed_tx}
Entonces simplemente invocamos
my_string_var = fmt.Sprintf("%x", ts.getRlp(0))
Que contendrá la cadena de transacción sin procesar deseada
f88b80881bc16d674ec80000830186a0941737b4e8e4101334b1b1965d3d739c41cc54f09680a4deaa59df000000000000000000000000cbfdfb9fb838b9090a7fe1976ed98017632b44f178a00a484a59015d08e736f59edf07ffb32f73151fddec52885b1f29cbcfd7aac2039f842a3a63c2fb1771cd0495b93a4db94692d4733baa9e96c559ddc4ff600422
Crear una transacción sin procesar:
package main
import (
"context"
"crypto/ecdsa"
"encoding/hex"
"fmt"
"log"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethclient"
)
func main() {
client, err := ethclient.Dial("https://rinkeby.infura.io")
if err != nil {
log.Fatal(err)
}
privateKey, err := crypto.HexToECDSA("fad9c8855b740a0b7ed4c221dbad0f33a83a49cad6b3fe8d5817ac83d38b6a19")
if err != nil {
log.Fatal(err)
}
publicKey := privateKey.Public()
publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey)
if !ok {
log.Fatal("error casting public key to ECDSA")
}
fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA)
nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
if err != nil {
log.Fatal(err)
}
value := big.NewInt(1000000000000000000) // in wei (1 eth)
gasLimit := uint64(21000) // in units
gasPrice, err := client.SuggestGasPrice(context.Background())
if err != nil {
log.Fatal(err)
}
toAddress := common.HexToAddress("0x4592d8f8d7b001e72cb26a73e4fa1806a51ac79d")
var data []byte
tx := types.NewTransaction(nonce, toAddress, value, gasLimit, gasPrice, data)
chainID, err := client.NetworkID(context.Background())
if err != nil {
log.Fatal(err)
}
signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)
if err != nil {
log.Fatal(err)
}
ts := types.Transactions{signedTx}
rawTx := hex.EncodeToString(ts.GetRlp(0))
fmt.Printf(rawTx) // f86...772
}
Transmitiendo la transacción sin procesar:
package main
import (
"context"
"encoding/hex"
"fmt"
"log"
"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)
err = client.SendTransaction(context.Background(), tx)
if err != nil {
log.Fatal(err)
}
fmt.Printf("tx sent: %s", tx.Hash().Hex()) // tx sent: 0xc429e5f128387d224ba8bed6885e86525e14bfdc2eb24b5e9c3351a1176fd81f
}
"Creación de transacciones sin conexión/sin procesar con Go-Ethereum" @akshay_111meher https://medium.com/@akshay_111meher/creating-offline-raw-transactions-with-go-ethereum-8d6cc8174c5d
ethereum_alex
data
campo en uno de los tipos geth:common.FromHex(string(data))
, dondedata
está my[]byte
.Ciberciencia
Enrique Alcázar