Reputation: 2719
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
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
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