// (c) 2019-2020, Ava Labs, Inc. All rights reserved. // See the file LICENSE for licensing terms. package avm import ( "bytes" "errors" "sort" "github.com/ava-labs/gecko/utils" "github.com/ava-labs/gecko/vms/components/ava" "github.com/ava-labs/gecko/vms/components/codec" "github.com/ava-labs/gecko/vms/components/verify" ) var ( errNilOperation = errors.New("nil operation is not valid") errNilFxOperation = errors.New("nil fx operation is not valid") errNotSortedAndUniqueUTXOIDs = errors.New("utxo IDs not sorted and unique") ) // Operation ... type Operation struct { ava.Asset `serialize:"true"` UTXOIDs []*ava.UTXOID `serialize:"true" json:"inputIDs"` Op FxOperation `serialize:"true" json:"operation"` } // Verify implements the verify.Verifiable interface func (op *Operation) Verify(c codec.Codec) error { switch { case op == nil: return errNilOperation case op.Op == nil: return errNilFxOperation case !ava.IsSortedAndUniqueUTXOIDs(op.UTXOIDs): return errNotSortedAndUniqueUTXOIDs default: return verify.All(&op.Asset, op.Op) } } type innerSortOperation struct { ops []*Operation codec codec.Codec } func (ops *innerSortOperation) Less(i, j int) bool { iOp := ops.ops[i] jOp := ops.ops[j] iBytes, err := ops.codec.Marshal(iOp) if err != nil { return false } jBytes, err := ops.codec.Marshal(jOp) if err != nil { return false } return bytes.Compare(iBytes, jBytes) == -1 } func (ops *innerSortOperation) Len() int { return len(ops.ops) } func (ops *innerSortOperation) Swap(i, j int) { o := ops.ops; o[j], o[i] = o[i], o[j] } func sortOperations(ops []*Operation, c codec.Codec) { sort.Sort(&innerSortOperation{ops: ops, codec: c}) } func isSortedAndUniqueOperations(ops []*Operation, c codec.Codec) bool { return utils.IsSortedAndUnique(&innerSortOperation{ops: ops, codec: c}) }