github.com/hyperledger/burrow@v0.34.5-0.20220512172541-77f09336001d/execution/native/natives.go (about)

     1  // Copyright Monax Industries Limited
     2  // SPDX-License-Identifier: Apache-2.0
     3  
     4  package native
     5  
     6  import (
     7  	"fmt"
     8  
     9  	"github.com/hyperledger/burrow/acm"
    10  	"github.com/hyperledger/burrow/crypto"
    11  	"github.com/hyperledger/burrow/execution/engine"
    12  	"github.com/hyperledger/burrow/logging"
    13  	"github.com/hyperledger/burrow/permission"
    14  )
    15  
    16  type Natives struct {
    17  	callableByAddress map[crypto.Address]engine.Native
    18  	callableByName    map[string]engine.Native
    19  	logger            *logging.Logger
    20  }
    21  
    22  func New() *Natives {
    23  	return &Natives{
    24  		callableByAddress: make(map[crypto.Address]engine.Native),
    25  		callableByName:    make(map[string]engine.Native),
    26  		logger:            logging.NewNoopLogger(),
    27  	}
    28  }
    29  
    30  func Merge(nss ...*Natives) (*Natives, error) {
    31  	n := New()
    32  	for _, ns := range nss {
    33  		for _, contract := range ns.callableByName {
    34  			err := n.register(contract)
    35  			if err != nil {
    36  				return nil, err
    37  			}
    38  		}
    39  	}
    40  	return n, nil
    41  }
    42  
    43  func (ns *Natives) WithLogger(logger *logging.Logger) *Natives {
    44  	ns.logger = logger
    45  	return ns
    46  }
    47  
    48  func (ns *Natives) Dispatch(acc *acm.Account) engine.Callable {
    49  	return ns.GetByAddress(acc.Address)
    50  }
    51  
    52  func (ns *Natives) SetExternals(externals engine.Dispatcher) {
    53  	for _, c := range ns.callableByAddress {
    54  		c.SetExternals(externals)
    55  	}
    56  }
    57  
    58  func (ns *Natives) Callables() []engine.Callable {
    59  	callables := make([]engine.Callable, 0, len(ns.callableByAddress))
    60  	for _, c := range ns.callableByAddress {
    61  		callables = append(callables, c)
    62  	}
    63  	return callables
    64  }
    65  
    66  func (ns *Natives) GetByName(name string) engine.Native {
    67  	return ns.callableByName[name]
    68  }
    69  
    70  func (ns *Natives) GetContract(name string) *Contract {
    71  	c, _ := ns.GetByName(name).(*Contract)
    72  	return c
    73  }
    74  
    75  func (ns *Natives) GetFunction(name string) *Function {
    76  	f, _ := ns.GetByName(name).(*Function)
    77  	return f
    78  }
    79  
    80  func (ns *Natives) GetByAddress(address crypto.Address) engine.Native {
    81  	return ns.callableByAddress[address]
    82  }
    83  
    84  func (ns *Natives) IsRegistered(address crypto.Address) bool {
    85  	_, ok := ns.callableByAddress[address]
    86  	return ok
    87  }
    88  
    89  func (ns *Natives) MustContract(name, comment string, functions ...Function) *Natives {
    90  	ns, err := ns.Contract(name, comment, functions...)
    91  	if err != nil {
    92  		panic(err)
    93  	}
    94  	return ns
    95  }
    96  
    97  func (ns *Natives) Contract(name, comment string, functions ...Function) (*Natives, error) {
    98  	contract, err := NewContract(name, comment, ns.logger, functions...)
    99  	if err != nil {
   100  		return nil, err
   101  	}
   102  	err = ns.register(contract)
   103  	if err != nil {
   104  		return nil, err
   105  	}
   106  	return ns, nil
   107  }
   108  
   109  func (ns *Natives) MustFunction(comment string, address crypto.Address, permFlag permission.PermFlag, f interface{}) *Natives {
   110  	ns, err := ns.Function(comment, address, permFlag, f)
   111  	if err != nil {
   112  		panic(err)
   113  	}
   114  	return ns
   115  }
   116  
   117  func (ns *Natives) Function(comment string, address crypto.Address, permFlag permission.PermFlag, f interface{}) (*Natives, error) {
   118  	function, err := NewFunction(comment, address, permFlag, f)
   119  	if err != nil {
   120  		return nil, err
   121  	}
   122  	err = ns.register(function)
   123  	if err != nil {
   124  		return nil, err
   125  	}
   126  	return ns, nil
   127  }
   128  
   129  func (ns *Natives) register(callable engine.Native) error {
   130  	name := callable.FullName()
   131  	address := callable.Address()
   132  	_, ok := ns.callableByName[name]
   133  	if ok {
   134  		return fmt.Errorf("cannot redeclare contract with name %s", name)
   135  	}
   136  	_, ok = ns.callableByAddress[address]
   137  	if ok {
   138  		return fmt.Errorf("cannot redeclare contract with address %v", address)
   139  	}
   140  	ns.callableByName[name] = callable
   141  	ns.callableByAddress[address] = callable
   142  	return nil
   143  }