TBouder
TBouder

Reputation: 2719

How to get the result and the status of a transaction

I am trying to work with the Ethereum blockchain, with the Solidity contracts. I am currently deploying a contract and performing some actions on it, but I would like to know how to get some 'feedback/callback/returns' of a specific transaction.

Is there a way to set the status of a transaction to 0 (error) and still get events, for example ?

if (id.length <= 0) {
    emit Result("KO", "1");
    revert();
} 

This will not work (no event) because I revert everything, but the status will be set to 0

if (id.length <= 0) {
    emit Result("KO", "1");
    return;
} 

I will get some event, but the status will stay 1

if (id.length <= 0) {
    revert("KO_1");
} 

The status will be 0, but I will not have any event

Here is my go code to perform the action :

func    testFunction(id []byte) {
    //...
    //...
    tx, err := instance.Action(opt, id)
    if (errors.HasError(err)) {
        return
    }
    callbackValue := subscribeToContract(tx.Hash().Hex())
    logs.Pretty(tx, callbackValue)
    //...
    //...
}

func    subscribeToContract(hashToRead string) myStruct {
    query := ethereum.FilterQuery{
        Addresses: []common.Address{address},
    }
    soc := make(chan types.Log)

    sub, err := WssClient.SubscribeFilterLogs(context.Background(), query, soc)
    if err != nil {
        logs.Error(err)
    }

    for {
        select {
        case err := <-sub.Err():
            logs.Info(`SOMETHING ERROR`)
            logs.Error(err)
        case vLog := <-soc:
        logs.Info(`SOMETHING`)
        contractAbi, _ := abi.JSON(strings.NewReader(string(SignABI)))  
        event := myStruct{}
    contractAbi.Unpack(&event, "Result", vLog.Data)
    logs.Info(`New Event from [` + vLog.TxHash.Hex() + `] : ` + event.Message)
        }
    }
}

If id.length > 0, all good. But if id.length <= 0, I have no callback from the subscribeToContract function.

Is there a way to directly have the result status, or should loop with tx, err := client.TransactionReceipt(context.Background(), txHash) until I get a Status?

Upvotes: 4

Views: 10240

Answers (2)

rachid chami
rachid chami

Reputation: 33

An easier/newer solution:

I think the function waitMined is the function you are looking for.

bind.WaitMined(context.Background(), client, signedTx)

Originally posted in here.

Upvotes: 0

TBouder
TBouder

Reputation: 2719

I didn't found any way to subscribe to a specific status change for a transaction, but a workaround :
The go-ethereum package provides 2 functions SubscribeFilterLogs and SubscribeNewHead. We can use the first one to get the logs (if relevant) and the second one to get a block information :

SubscribeNewHead subscribes to notifications about the current blockchain head on the given channel.

A transaction can be validated or rejected/reverted when a block is mined, so we can use this 'trick'

func checkTransactionReceipt(_txHash string) int {
    client, _ := getClient("https://ropsten.infura.io/v3/XXXXXX")
    txHash := common.HexToHash(_txHash)
    tx, err := client.TransactionReceipt(context.Background(), txHash)
    if (Error.HasError(err)) {
        return (-1)
    }
    return (int(tx.Status))
}

func    WaitForBlockCompletation(data EthData, hashToRead string) int {
    soc := make(chan *types.Header)
    sub, err := data.WssClient.SubscribeNewHead(context.Background(), soc)
    if (err != nil) {
        return -1
    }

    for {
        select {
            case err := <-sub.Err():
                _ = err
                return -1
            case header := <-soc:
                logs.Info(header.TxHash.Hex())
                transactionStatus := checkTransactionReceipt(hashToRead)
                if (transactionStatus == 0) {
                    //FAILURE
                    sub.Unsubscribe()
                    return 0
                } else if (transactionStatus == 1) {
                    //SUCCESS
                    sub.Unsubscribe()
                    return 1
                }
        }
    }
}

Basically we are waiting for the block to be mined, then we check the TransactionReceipt which fail with an error (not found) if the transaction is not yet validated/rejected. Then, if the transaction is, we can unsubscribe the subscription and return the transaction status (0 fail, 1 success).

Not sure if it's the worst, best, only method, but it's working ! Be free to improve this solution !

Upvotes: 4

Related Questions