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

     1  package engine
     2  
     3  import (
     4  	"github.com/hyperledger/burrow/acm"
     5  )
     6  
     7  type Dispatcher interface {
     8  	// If this Dispatcher is capable of dispatching this account (e.g. if it has the correct bytecode) then return a
     9  	// Callable that wraps the function, otherwise return nil
    10  	Dispatch(acc *acm.Account) Callable
    11  }
    12  
    13  type DispatcherFunc func(acc *acm.Account) Callable
    14  
    15  func (d DispatcherFunc) Dispatch(acc *acm.Account) Callable {
    16  	return d(acc)
    17  }
    18  
    19  // An ExternalDispatcher is able to Dispatch accounts to external engines as well as Dispatch to itself
    20  type ExternalDispatcher interface {
    21  	Dispatcher
    22  	SetExternals(externals Dispatcher)
    23  }
    24  
    25  // An ExternalDispatcher is able to Dispatch accounts to external engines as well as Dispatch to itself
    26  type Externals struct {
    27  	// Provide any foreign dispatchers to allow calls between VMs
    28  	externals Dispatcher
    29  }
    30  
    31  var _ ExternalDispatcher = (*Externals)(nil)
    32  
    33  func (ed *Externals) Dispatch(acc *acm.Account) Callable {
    34  	// Try external calls then fallback to EVM
    35  	if ed.externals == nil {
    36  		return nil
    37  	}
    38  	return ed.externals.Dispatch(acc)
    39  }
    40  
    41  func (ed *Externals) SetExternals(externals Dispatcher) {
    42  	ed.externals = externals
    43  }
    44  
    45  type Dispatchers []Dispatcher
    46  
    47  func NewDispatchers(dispatchers ...Dispatcher) Dispatchers {
    48  	out := dispatchers[:0]
    49  	// Flatten dispatchers and omit nil dispatchers (allows optional dispatchers in chain)
    50  	for i, d := range dispatchers {
    51  		ds, ok := d.(Dispatchers)
    52  		if ok {
    53  			// Add tail to nested dispatchers if one exists
    54  			if len(dispatchers) > i {
    55  				ds = append(ds, dispatchers[i+1:]...)
    56  			}
    57  			return append(out, NewDispatchers(ds...)...)
    58  		} else if d != nil {
    59  			out = append(out, d)
    60  		}
    61  	}
    62  	return out
    63  }
    64  
    65  // Connect ExternalDispatchers eds to each other so that the underlying engines can mutually call contracts hosted by
    66  // other dispatchers
    67  func Connect(eds ...ExternalDispatcher) {
    68  	for i, ed := range eds {
    69  		// Collect external dispatchers excluding this one (to avoid infinite dispatcher loops!)
    70  		others := make([]Dispatcher, 0, len(eds)-1)
    71  		for offset := 1; offset < len(eds); offset++ {
    72  			idx := (i + offset) % len(eds)
    73  			others = append(others, eds[idx])
    74  		}
    75  		ed.SetExternals(NewDispatchers(others...))
    76  	}
    77  }
    78  
    79  func (ds Dispatchers) Dispatch(acc *acm.Account) Callable {
    80  	for _, d := range ds {
    81  		callable := d.Dispatch(acc)
    82  		if callable != nil {
    83  			return callable
    84  		}
    85  	}
    86  	return nil
    87  }
    88  
    89  type ExternalsStorage struct {
    90  }