Decodificar transacción sin procesar

¿Cómo puedo decodificar una transacción sin procesar usando Go/go-ethereum? No existe un método/función para leer los bytes sin formato o el hexadecimal en una transacción https://godoc.org/github.com/ethereum/go-ethereum/core/types . Básicamente, solo quiero extraer la dirección de destino y la cantidad enviada.

Voté para cerrar esto como un duplicado de ethereum.stackexchange.com/questions/4196/… . Si cree que no es un duplicado o por alguna razón no está satisfecho con las respuestas a esa pregunta, edite la pregunta explicando por qué debe reabrirse.
@AjoyBhatia Esta pregunta parece ser específicamente sobre cómo hacer esto usando go-ethereum.
@smarx - Eso es correcto. Me retracté de mi voto de cierre

Respuestas (4)

Usando el paquete oficial de go-ethereum:

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
}

Mire los métodos del Transactiontipo para acceder a los datos en el objeto tx.

Aquí hay un código de trabajo en github

¿Puedo preguntar qué estás haciendo en ese bucle para decodificar la clave pública? ¿Qué son sig1 y sig2 y por qué necesita una clave pública?
@Nulik Para el uso normal de blockchain, no necesita una clave pública. Pero si desea investigar o profundizar en la criptografía EC, es posible que esté ansioso por encontrar una clave pública. En mi código sig1 y sig2 hay una firma del mensaje. Consta de R+S+V (aprender más sobre las curvas elípticas). R y S son conocidos. V puede ser 00 o 01, así que solo marcamos ambas opciones.

Aquí hay un paquete que descubrí de esta respuesta :

https://github.com/ConsenSys/abi-decodificador

Consulte el bloque de código titulado Decodificar datos Tx . Creo que esto debería hacer lo que quieres.

¿Puedes entender la diferencia entre javascript y Go?
De acuerdo. De acuerdo. Debería leer las preguntas con más atención. go-ethereum también tiene una API de Javascript para comunicarse con el nodo mediante IPC o RPC. Eso es lo que siempre he usado porque programé en Javascript. Tal vez, cuando dijo Go / go-ethereum , ¿se refería a una aplicación en Go (es decir, no Javascript) que interactúa con el cliente go-ethereum?

Aquí hay un ejemplo completo de cómo leer los valores de transacción (es decir, desde la dirección, el valor ético, etc.) en 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
    }
}

Si tiene el hexadecimal tx sin procesar, así es como puede decodificarlo en un tipo tx:

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)
}

Con la introducción de EIP-1559, rlp.DecodeBytes(..)ya no funciona y tendrá que usarlo en su tx.UnmarshalBinary(..)lugar. Aquí hay un ejemplo :

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)
}

Alternativamente, puede extraer lo que quiera usando rlpdump.