diff options
Diffstat (limited to 'plugin/evm/tx.go')
-rw-r--r-- | plugin/evm/tx.go | 105 |
1 files changed, 105 insertions, 0 deletions
diff --git a/plugin/evm/tx.go b/plugin/evm/tx.go new file mode 100644 index 0000000..024e54d --- /dev/null +++ b/plugin/evm/tx.go @@ -0,0 +1,105 @@ +// (c) 2019-2020, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package evm + +import ( + "fmt" + + "github.com/ava-labs/gecko/database" + "github.com/ava-labs/gecko/database/versiondb" + "github.com/ava-labs/gecko/ids" + "github.com/ava-labs/gecko/snow" + "github.com/ava-labs/gecko/utils/codec" + "github.com/ava-labs/gecko/utils/crypto" + "github.com/ava-labs/gecko/utils/hashing" + "github.com/ava-labs/gecko/vms/components/verify" + "github.com/ava-labs/gecko/vms/secp256k1fx" +) + +// UnsignedTx is an unsigned transaction +type UnsignedTx interface { + Initialize(unsignedBytes, signedBytes []byte) + ID() ids.ID + UnsignedBytes() []byte + Bytes() []byte +} + +// UnsignedDecisionTx is an unsigned operation that can be immediately decided +type UnsignedDecisionTx interface { + UnsignedTx + + // Attempts to verify this transaction with the provided state. + SemanticVerify(vm *VM, db database.Database, stx *Tx) ( + onAcceptFunc func() error, + err TxError, + ) +} + +// UnsignedProposalTx is an unsigned operation that can be proposed +type UnsignedProposalTx interface { + UnsignedTx + + // Attempts to verify this transaction with the provided state. + SemanticVerify(vm *VM, db database.Database, stx *Tx) ( + onCommitDB *versiondb.Database, + onAbortDB *versiondb.Database, + onCommitFunc func() error, + onAbortFunc func() error, + err TxError, + ) + InitiallyPrefersCommit(vm *VM) bool +} + +// UnsignedAtomicTx is an unsigned operation that can be atomically accepted +type UnsignedAtomicTx interface { + UnsignedTx + + // UTXOs this tx consumes + InputUTXOs() ids.Set + // Attempts to verify this transaction with the provided state. + SemanticVerify(vm *VM, db database.Database, stx *Tx) TxError + + // Accept this transaction with the additionally provided state transitions. + Accept(ctx *snow.Context, batch database.Batch) error +} + +// Tx is a signed transaction +type Tx struct { + // The body of this transaction + UnsignedTx `serialize:"true" json:"unsignedTx"` + + // The credentials of this transaction + Creds []verify.Verifiable `serialize:"true" json:"credentials"` +} + +// Sign this transaction with the provided signers +func (tx *Tx) Sign(c codec.Codec, signers [][]*crypto.PrivateKeySECP256K1R) error { + unsignedBytes, err := c.Marshal(&tx.UnsignedTx) + if err != nil { + return fmt.Errorf("couldn't marshal UnsignedTx: %w", err) + } + + // Attach credentials + hash := hashing.ComputeHash256(unsignedBytes) + for _, keys := range signers { + cred := &secp256k1fx.Credential{ + Sigs: make([][crypto.SECP256K1RSigLen]byte, len(keys)), + } + for i, key := range keys { + sig, err := key.SignHash(hash) // Sign hash + if err != nil { + return fmt.Errorf("problem generating credential: %w", err) + } + copy(cred.Sigs[i][:], sig) + } + tx.Creds = append(tx.Creds, cred) // Attach credential + } + + signedBytes, err := c.Marshal(tx) + if err != nil { + return fmt.Errorf("couldn't marshal ProposalTx: %w", err) + } + tx.Initialize(unsignedBytes, signedBytes) + return nil +} |