github.com/hyperledger/burrow@v0.34.5-0.20220512172541-77f09336001d/deploy/def/job.go (about)

     1  package def
     2  
     3  import (
     4  	"regexp"
     5  
     6  	"reflect"
     7  
     8  	"fmt"
     9  
    10  	validation "github.com/go-ozzo/ozzo-validation"
    11  	"github.com/hyperledger/burrow/deploy/def/rule"
    12  	"github.com/hyperledger/burrow/execution/evm/abi"
    13  )
    14  
    15  // TODO: Interface all the jobs, determine if they should remain in definitions or get their own package
    16  
    17  type Job struct {
    18  	// Name of the job
    19  	Name string `mapstructure:"name,omitempty" json:"name,omitempty" yaml:"name,omitempty" toml:"name"`
    20  	// Not marshalled
    21  	Intermediate interface{} `json:"-" yaml:"-" toml:"-"`
    22  	// Not marshalled
    23  	Result interface{} `json:"-" yaml:"-" toml:"-"`
    24  	// For multiple values
    25  	Variables []*abi.Variable `json:"-" yaml:"-" toml:"-"`
    26  	// Create proposal or vote for one
    27  	Proposal *Proposal `mapstructure:"proposal,omitempty" json:"proposal,omitempty" yaml:"proposal,omitempty" toml:"proposal"`
    28  	// Sets/Resets the primary account to use
    29  	Account *Account `mapstructure:"account,omitempty" json:"account,omitempty" yaml:"account,omitempty" toml:"account"`
    30  	// Set an arbitrary value
    31  	Set *Set `mapstructure:"set,omitempty" json:"set,omitempty" yaml:"set,omitempty" toml:"set"`
    32  	// Run a sequence of other deploy.yamls
    33  	Meta *Meta `mapstructure:"meta,omitempty" json:"meta,omitempty" yaml:"meta,omitempty" toml:"meta"`
    34  	// Issue a governance transaction
    35  	UpdateAccount *UpdateAccount `mapstructure:"update-account,omitempty" json:"update-account,omitempty" yaml:"update-account,omitempty" toml:"update-account"`
    36  	// Contract compile and send to the chain functions
    37  	Deploy *Deploy `mapstructure:"deploy,omitempty" json:"deploy,omitempty" yaml:"deploy,omitempty" toml:"deploy"`
    38  	// Contract compile/build
    39  	Build *Build `mapstructure:"build,omitempty" json:"build,omitempty" yaml:"build,omitempty" toml:"build"`
    40  	// Send tokens from one account to another
    41  	Send *Send `mapstructure:"send,omitempty" json:"send,omitempty" yaml:"send,omitempty" toml:"send"`
    42  	// Bond tokens from an account
    43  	Bond *Bond `mapstructure:"bond,omitempty" json:"bond,omitempty" yaml:"bond,omitempty" toml:"bond"`
    44  	// Unbond tokens from an account
    45  	Unbond *Unbond `mapstructure:"unbond,omitempty" json:"unbond,omitempty" yaml:"unbond,omitempty" toml:"unbond"`
    46  	// Utilize monax:db's native name registry to register a name
    47  	RegisterName *RegisterName `mapstructure:"register,omitempty" json:"register,omitempty" yaml:"register,omitempty" toml:"register"`
    48  	// Validator identify as node key
    49  	Identify *Identify `mapstructure:"identify,omitempty" json:"identify,omitempty" yaml:"identify,omitempty" toml:"identify"`
    50  	// Sends a transaction which will update the permissions of an account. Must be sent from an account which
    51  	// has root permissions on the blockchain (as set by either the genesis.json or in a subsequence transaction)
    52  	Permission *Permission `mapstructure:"permission,omitempty" json:"permission,omitempty" yaml:"permission,omitempty" toml:"permission"`
    53  	// Sends a transaction to a contract. Will utilize monax-abi under the hood to perform all of the heavy lifting
    54  	Call *Call `mapstructure:"call,omitempty" json:"call,omitempty" yaml:"call,omitempty" toml:"call"`
    55  	// Wrapper for mintdump dump. WIP
    56  	DumpState *DumpState `mapstructure:"dump-state,omitempty" json:"dump-state,omitempty" yaml:"dump-state,omitempty" toml:"dump-state"`
    57  	// Wrapper for mintdum restore. WIP
    58  	RestoreState *RestoreState `mapstructure:"restore-state,omitempty" json:"restore-state,omitempty" yaml:"restore-state,omitempty" toml:"restore-state"`
    59  	// Sends a "simulated call,omitempty" to a contract. Predominantly used for accessor functions ("Getters,omitempty" within contracts)
    60  	QueryContract *QueryContract `mapstructure:"query-contract,omitempty" json:"query-contract,omitempty" yaml:"query-contract,omitempty" toml:"query-contract"`
    61  	// Queries information from an account.
    62  	QueryAccount *QueryAccount `mapstructure:"query-account,omitempty" json:"query-account,omitempty" yaml:"query-account,omitempty" toml:"query-account"`
    63  	// Queries information about a name registered with monax:db's native name registry
    64  	QueryName *QueryName `mapstructure:"query-name,omitempty" json:"query-name,omitempty" yaml:"query-name,omitempty" toml:"query-name"`
    65  	// Queries information about the validator set
    66  	QueryVals *QueryVals `mapstructure:"query-vals,omitempty" json:"query-vals,omitempty" yaml:"query-vals,omitempty" toml:"query-vals"`
    67  	// Makes and assertion (useful for testing purposes)
    68  	Assert *Assert `mapstructure:"assert,omitempty" json:"assert,omitempty" yaml:"assert,omitempty" toml:"assert"`
    69  }
    70  
    71  type Payload interface {
    72  	validation.Validatable
    73  }
    74  
    75  func (job *Job) Validate() error {
    76  	payloadField, err := job.PayloadField()
    77  	if err != nil {
    78  		return err
    79  	}
    80  	return validation.ValidateStruct(job,
    81  		validation.Field(&job.Name, validation.Required, validation.Match(regexp.MustCompile("[[:word:]]+")).
    82  			Error("must contain word characters; alphanumeric plus underscores/hyphens")),
    83  		validation.Field(&job.Result, rule.New(rule.IsOmitted, "internally reserved and should be removed")),
    84  		validation.Field(&job.Variables, rule.New(rule.IsOmitted, "internally reserved and should be removed")),
    85  		validation.Field(payloadField.Addr().Interface()),
    86  	)
    87  }
    88  
    89  var payloadType = reflect.TypeOf((*Payload)(nil)).Elem()
    90  
    91  func (job *Job) Payload() (Payload, error) {
    92  	field, err := job.PayloadField()
    93  	if err != nil {
    94  		return nil, err
    95  	}
    96  	return field.Interface().(Payload), nil
    97  }
    98  
    99  // Ensures only one Job payload is set and returns a pointer to that field or an error if none or multiple
   100  // job payload fields are set
   101  func (job *Job) PayloadField() (reflect.Value, error) {
   102  	rv := reflect.ValueOf(job).Elem()
   103  	rt := rv.Type()
   104  
   105  	payloadIndex := -1
   106  	for i := 0; i < rt.NumField(); i++ {
   107  		if rt.Field(i).Type.Implements(payloadType) && !rv.Field(i).IsNil() {
   108  			if payloadIndex >= 0 {
   109  				return reflect.Value{}, fmt.Errorf("only one Job payload field should be set, but both '%v' and '%v' are set",
   110  					rt.Field(payloadIndex).Name, rt.Field(i).Name)
   111  			}
   112  			payloadIndex = i
   113  		}
   114  	}
   115  	if payloadIndex == -1 {
   116  		return reflect.Value{}, fmt.Errorf("Job has no payload, please set at least one job value")
   117  	}
   118  
   119  	return rv.Field(payloadIndex), nil
   120  }