github.com/Tri-stone/burrow@v0.25.0/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  	// Utilize monax:db's native name registry to register a name
    43  	RegisterName *RegisterName `mapstructure:"register,omitempty" json:"register,omitempty" yaml:"register,omitempty" toml:"register"`
    44  	// Sends a transaction which will update the permissions of an account. Must be sent from an account which
    45  	// has root permissions on the blockchain (as set by either the genesis.json or in a subsequence transaction)
    46  	Permission *Permission `mapstructure:"permission,omitempty" json:"permission,omitempty" yaml:"permission,omitempty" toml:"permission"`
    47  	// Sends a transaction to a contract. Will utilize monax-abi under the hood to perform all of the heavy lifting
    48  	Call *Call `mapstructure:"call,omitempty" json:"call,omitempty" yaml:"call,omitempty" toml:"call"`
    49  	// Wrapper for mintdump dump. WIP
    50  	DumpState *DumpState `mapstructure:"dump-state,omitempty" json:"dump-state,omitempty" yaml:"dump-state,omitempty" toml:"dump-state"`
    51  	// Wrapper for mintdum restore. WIP
    52  	RestoreState *RestoreState `mapstructure:"restore-state,omitempty" json:"restore-state,omitempty" yaml:"restore-state,omitempty" toml:"restore-state"`
    53  	// Sends a "simulated call,omitempty" to a contract. Predominantly used for accessor functions ("Getters,omitempty" within contracts)
    54  	QueryContract *QueryContract `mapstructure:"query-contract,omitempty" json:"query-contract,omitempty" yaml:"query-contract,omitempty" toml:"query-contract"`
    55  	// Queries information from an account.
    56  	QueryAccount *QueryAccount `mapstructure:"query-account,omitempty" json:"query-account,omitempty" yaml:"query-account,omitempty" toml:"query-account"`
    57  	// Queries information about a name registered with monax:db's native name registry
    58  	QueryName *QueryName `mapstructure:"query-name,omitempty" json:"query-name,omitempty" yaml:"query-name,omitempty" toml:"query-name"`
    59  	// Queries information about the validator set
    60  	QueryVals *QueryVals `mapstructure:"query-vals,omitempty" json:"query-vals,omitempty" yaml:"query-vals,omitempty" toml:"query-vals"`
    61  	// Makes and assertion (useful for testing purposes)
    62  	Assert *Assert `mapstructure:"assert,omitempty" json:"assert,omitempty" yaml:"assert,omitempty" toml:"assert"`
    63  }
    64  
    65  type Payload interface {
    66  	validation.Validatable
    67  }
    68  
    69  func (job *Job) Validate() error {
    70  	payloadField, err := job.PayloadField()
    71  	if err != nil {
    72  		return err
    73  	}
    74  	return validation.ValidateStruct(job,
    75  		validation.Field(&job.Name, validation.Required, validation.Match(regexp.MustCompile("[[:word:]]+")).
    76  			Error("must contain word characters; alphanumeric plus underscores/hyphens")),
    77  		validation.Field(&job.Result, rule.New(rule.IsOmitted, "internally reserved and should be removed")),
    78  		validation.Field(&job.Variables, rule.New(rule.IsOmitted, "internally reserved and should be removed")),
    79  		validation.Field(payloadField.Addr().Interface()),
    80  	)
    81  }
    82  
    83  var payloadType = reflect.TypeOf((*Payload)(nil)).Elem()
    84  
    85  func (job *Job) Payload() (Payload, error) {
    86  	field, err := job.PayloadField()
    87  	if err != nil {
    88  		return nil, err
    89  	}
    90  	return field.Interface().(Payload), nil
    91  }
    92  
    93  // Ensures only one Job payload is set and returns a pointer to that field or an error if none or multiple
    94  // job payload fields are set
    95  func (job *Job) PayloadField() (reflect.Value, error) {
    96  	rv := reflect.ValueOf(job).Elem()
    97  	rt := rv.Type()
    98  
    99  	payloadIndex := -1
   100  	for i := 0; i < rt.NumField(); i++ {
   101  		if rt.Field(i).Type.Implements(payloadType) && !rv.Field(i).IsNil() {
   102  			if payloadIndex >= 0 {
   103  				return reflect.Value{}, fmt.Errorf("only one Job payload field should be set, but both '%v' and '%v' are set",
   104  					rt.Field(payloadIndex).Name, rt.Field(i).Name)
   105  			}
   106  			payloadIndex = i
   107  		}
   108  	}
   109  	if payloadIndex == -1 {
   110  		return reflect.Value{}, fmt.Errorf("Job has no payload, please set at least one job value")
   111  	}
   112  
   113  	return rv.Field(payloadIndex), nil
   114  }