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 }