github.com/hyperledger/burrow@v0.34.5-0.20220512172541-77f09336001d/vent/service/abi_provider.go (about)

     1  package service
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  
     7  	"github.com/hyperledger/burrow/crypto"
     8  	"github.com/hyperledger/burrow/execution/evm/abi"
     9  	"github.com/hyperledger/burrow/logging"
    10  	"github.com/hyperledger/burrow/vent/chain"
    11  )
    12  
    13  type EventSpecGetter func(abi.EventID, crypto.Address) (*abi.EventSpec, error)
    14  
    15  // AbiProvider provides a method for loading ABIs from disk, and retrieving them from burrow on-demand
    16  type AbiProvider struct {
    17  	abiSpec *abi.Spec
    18  	chain   chain.Chain
    19  	logger  *logging.Logger
    20  }
    21  
    22  // NewAbiProvider loads ABIs from the filesystem. A set of zero or more files or directories can be passed in the path
    23  // argument. If an event is encountered for which no ABI is known, it is retrieved from burrow
    24  func NewAbiProvider(paths []string, chain chain.Chain, logger *logging.Logger) (provider *AbiProvider, err error) {
    25  	abiSpec := abi.NewSpec()
    26  	if len(paths) > 0 {
    27  		abiSpec, err = abi.LoadPath(paths...)
    28  		if err != nil {
    29  			return nil, err
    30  		}
    31  	}
    32  
    33  	provider = &AbiProvider{
    34  		abiSpec: abiSpec,
    35  		chain:   chain,
    36  		logger:  logger.WithScope("NewAbiProvider"),
    37  	}
    38  	return
    39  }
    40  
    41  // GetEventAbi get the ABI for a particular eventID. If it is not known, it is retrieved from the burrow node via
    42  // the address for the contract
    43  func (p *AbiProvider) GetEventAbi(eventID abi.EventID, address crypto.Address) (*abi.EventSpec, error) {
    44  	evAbi, ok := p.abiSpec.EventsByID[eventID]
    45  	if !ok {
    46  		metadata, err := p.chain.GetABI(context.Background(), address)
    47  		if err != nil {
    48  			p.logger.InfoMsg("Error retrieving abi for event", "address", address.String(), "eventid", eventID.String(), "error", err)
    49  			return nil, err
    50  		}
    51  		if metadata == "" {
    52  			p.logger.InfoMsg("ABI not found for contract", "address", address.String(), "eventid", eventID.String())
    53  			return nil, fmt.Errorf("No ABI present for contract at address %v", address)
    54  		}
    55  		a, err := abi.ReadSpec([]byte(metadata))
    56  		if err != nil {
    57  			p.logger.InfoMsg("Failed to parse abi", "address", address.String(), "eventid", eventID.String(), "abi", metadata)
    58  			return nil, err
    59  		}
    60  		evAbi, ok = a.EventsByID[eventID]
    61  		if !ok {
    62  			p.logger.InfoMsg("Event missing from ABI spec for contract", "address", address.String(), "eventid", eventID.String(), "abi", metadata)
    63  			return nil, fmt.Errorf("Event missing from ABI spec for contract")
    64  		}
    65  
    66  		p.abiSpec = abi.MergeSpec([]*abi.Spec{p.abiSpec, a})
    67  	}
    68  
    69  	return evAbi, nil
    70  }