¿Existe una característica distintiva de una transacción de 'creación de contrato'?

Mira esta transacción:

https://etherscan.io/tx/0x37c469573ca24f538d91f39e9d0b8d49927a36d70496ef74521cbf5c44a056d4

En la consola de geth, si ingreso:

eth.getTransaction('0x37c4...')

Devuelve la transacción con un tovalor de null. Estoy bastante seguro de que esto se debe a que esta transacción es una implementación de contrato.

Si miro:

eth.getTransactionReceipt('0x37c4...')

con el mismo ID de transacción, el contract addresscampo no está vacío.

Mi pregunta: ¿es tosuficiente nullpara distinguir una transacción como aquella que implementó un contrato? Y en segundo lugar, ¿mirar el recibo es la única forma de obtener la dirección del contrato?

Respuestas (1)

¿ Q está tosiendo nullsuficiente para distinguir una transacción como aquella que desplegó un contrato?

¿ Q es mirando el recibo la única manera de obtener la dirección del contrato?

Sí, en el cliente go-ethereum. , aunque probablemente también pueda averiguar la dirección del contrato a partir de los resultados de rastreo de la debug.traceTransaction(...)llamada a la API.

EDITAR: busqué en los debug.traceTransaction(...)resultados y no pude encontrar la dirección del contrato creado.



Desde el código fuente de go-ethereum eth/api.go, líneas 481-504 a continuación, puede ver que la condición donde se usa la Todirección para decidir si la transacción es una transacción de creación de contrato:nil

func (s *PrivateAccountAPI) SignAndSendTransaction(args SendTxArgs, passwd string) (common.Hash, error) {
    args = prepareSendTxArgs(args, s.gpo)

    s.txMu.Lock()
    defer s.txMu.Unlock()

    if args.Nonce == nil {
        args.Nonce = rpc.NewHexNumber(s.txPool.State().GetNonce(args.From))
    }

    var tx *types.Transaction
    if args.To == nil {
        tx = types.NewContractCreation(args.Nonce.Uint64(), args.Value.BigInt(), args.Gas.BigInt(), args.GasPrice.BigInt(), common.FromHex(args.Data))
    } else {
        tx = types.NewTransaction(args.Nonce.Uint64(), *args.To, args.Value.BigInt(), args.Gas.BigInt(), args.GasPrice.BigInt(), common.FromHex(args.Data))
    }

    signature, err := s.am.SignWithPassphrase(args.From, passwd, tx.SigHash().Bytes())
    if err != nil {
        return common.Hash{}, err
    }

    return submitTransaction(s.txPool, tx, signature)
}

Esto se confirma en 4.3 La Transacción en el Libro Amarillo :ingrese la descripción de la imagen aquí

donde el símbolo ∅ representa un conjunto vacío.

La búsqueda en el código fuente de go-ethereum para contractAddress muestra que ese getTransactionReceipt(...)es el método para devolver la dirección del contrato. De eth/api.go, líneas 1083-1132 :

func (s *PublicTransactionPoolAPI) GetTransactionReceipt(txHash common.Hash) (map[string]interface{}, error) {
    receipt := core.GetReceipt(s.chainDb, txHash)
    if receipt == nil {
        glog.V(logger.Debug).Infof("receipt not found for transaction %s", txHash.Hex())
        return nil, nil
    }

    tx, _, err := getTransaction(s.chainDb, s.txPool, txHash)
    if err != nil {
        glog.V(logger.Debug).Infof("%v\n", err)
        return nil, nil
    }

    txBlock, blockIndex, index, err := getTransactionBlockData(s.chainDb, txHash)
    if err != nil {
        glog.V(logger.Debug).Infof("%v\n", err)
        return nil, nil
    }

    from, err := tx.FromFrontier()
    if err != nil {
        glog.V(logger.Debug).Infof("%v\n", err)
        return nil, nil
    }

    fields := map[string]interface{}{
        "root":              common.Bytes2Hex(receipt.PostState),
        "blockHash":         txBlock,
        "blockNumber":       rpc.NewHexNumber(blockIndex),
        "transactionHash":   txHash,
        "transactionIndex":  rpc.NewHexNumber(index),
        "from":              from,
        "to":                tx.To(),
        "gasUsed":           rpc.NewHexNumber(receipt.GasUsed),
        "cumulativeGasUsed": rpc.NewHexNumber(receipt.CumulativeGasUsed),
        "contractAddress":   nil,
        "logs":              receipt.Logs,
    }

    if receipt.Logs == nil {
        fields["logs"] = []vm.Logs{}
    }

    // If the ContractAddress is 20 0x0 bytes, assume it is not a contract creation
    if bytes.Compare(receipt.ContractAddress.Bytes(), bytes.Repeat([]byte{0}, 20)) != 0 {
        fields["contractAddress"] = receipt.ContractAddress
    }

    return fields, nil
}
Hice esta pregunta para que pudieras responderla. Sabía que lo sabrías. Gracias.
Hola @Thomas, he estado esperando durante bastante tiempo que hagas esta pregunta exacta :-)