github.com/TrueBlocks/trueblocks-core/src/apps/chifra@v0.0.0-20241022031540-b362680128f7/pkg/articulate/transaction.go (about)

     1  package articulate
     2  
     3  import (
     4  	"errors"
     5  
     6  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/abi"
     7  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/decode"
     8  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/rpc"
     9  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/types"
    10  )
    11  
    12  func (abiCache *AbiCache) ArticulateTransaction(tx *types.Transaction) error {
    13  	// TODO: This `Articulate` function is different from the other ones (for Log, etc.) because it
    14  	// TODO: doesn't try to articulate the transaction by selector first.  It should.  But it doesn't.
    15  	// TODO: The reason it doesn't is because of conflicting four-bytes (for example, `donate`)
    16  	// if found, message, err := articulateTx(tx, &abiCache.AbiMap); err != nil {
    17  	// 	return err
    18  	//
    19  	// } else if found != nil {
    20  	// 	tx.ArticulatedTx = found
    21  	// 	tx.Message = message
    22  	//
    23  	// } else {
    24  	var err error
    25  	address := tx.To
    26  	if !abiCache.loadedMap.GetValue(address) && !abiCache.skipMap.GetValue(address) {
    27  		if err = abi.LoadAbi(abiCache.Conn, address, &abiCache.AbiMap); err != nil {
    28  			abiCache.skipMap.SetValue(address, true)
    29  			if !errors.Is(err, rpc.ErrNotAContract) {
    30  				// Not being a contract is not an error because we want to articulate the input in case it's a message
    31  				return err
    32  			}
    33  		} else {
    34  			abiCache.loadedMap.SetValue(address, true)
    35  		}
    36  	}
    37  
    38  	if !abiCache.skipMap.GetValue(address) {
    39  		if tx.ArticulatedTx, tx.Message, err = articulateTx(tx, &abiCache.AbiMap); err != nil {
    40  			return err
    41  		}
    42  	} else {
    43  		if message, ok := decode.ArticulateString(tx.Input); ok {
    44  			tx.Message = message
    45  		}
    46  	}
    47  	// }
    48  
    49  	if err = abiCache.ArticulateReceipt(tx.Receipt); err != nil {
    50  		return err
    51  	}
    52  
    53  	for index := range tx.Traces {
    54  		if err = abiCache.ArticulateTrace(&tx.Traces[index]); err != nil {
    55  			return err
    56  		}
    57  	}
    58  
    59  	return nil
    60  }
    61  
    62  func articulateTx(tx *types.Transaction, abiMap *abi.SelectorSyncMap) (*types.Function, string, error) {
    63  	var found *types.Function
    64  	var message string
    65  	var art *types.Function
    66  	var selector string
    67  	var input = tx.Input
    68  	var outputData string
    69  	if len(tx.Traces) > 0 && tx.Traces[0].Result != nil && len(tx.Traces[0].Result.Output) > 2 {
    70  		outputData = tx.Traces[0].Result.Output[2:]
    71  	}
    72  
    73  	if len(input) >= 10 {
    74  		selector = input[:10]
    75  		inputData := input[10:]
    76  		found = abiMap.GetValue(selector)
    77  		if found != nil {
    78  			art = found.Clone()
    79  			if err := ArticulateFunction(art, inputData, outputData); err != nil {
    80  				return found, "", err
    81  			}
    82  		}
    83  	}
    84  
    85  	if found == nil && len(input) > 0 {
    86  		var ok bool
    87  		var msg string
    88  		if msg, ok = decode.ArticulateString(tx.Input); ok {
    89  			message = msg
    90  		}
    91  	}
    92  
    93  	return art, message, nil
    94  }