mirror of https://github.com/poanetwork/gecko.git
Implemented Properties
This commit is contained in:
parent
a2c0ad56f7
commit
00332620a6
|
@ -24,6 +24,7 @@ import (
|
||||||
"github.com/ava-labs/gecko/vms/evm"
|
"github.com/ava-labs/gecko/vms/evm"
|
||||||
"github.com/ava-labs/gecko/vms/nftfx"
|
"github.com/ava-labs/gecko/vms/nftfx"
|
||||||
"github.com/ava-labs/gecko/vms/platformvm"
|
"github.com/ava-labs/gecko/vms/platformvm"
|
||||||
|
"github.com/ava-labs/gecko/vms/propertyfx"
|
||||||
"github.com/ava-labs/gecko/vms/secp256k1fx"
|
"github.com/ava-labs/gecko/vms/secp256k1fx"
|
||||||
"github.com/ava-labs/gecko/vms/spchainvm"
|
"github.com/ava-labs/gecko/vms/spchainvm"
|
||||||
"github.com/ava-labs/gecko/vms/spdagvm"
|
"github.com/ava-labs/gecko/vms/spdagvm"
|
||||||
|
@ -160,6 +161,7 @@ func Aliases(networkID uint32) (generalAliases map[string][]string, chainAliases
|
||||||
timestampvm.ID.Key(): []string{"timestamp"},
|
timestampvm.ID.Key(): []string{"timestamp"},
|
||||||
secp256k1fx.ID.Key(): []string{"secp256k1fx"},
|
secp256k1fx.ID.Key(): []string{"secp256k1fx"},
|
||||||
nftfx.ID.Key(): []string{"nftfx"},
|
nftfx.ID.Key(): []string{"nftfx"},
|
||||||
|
propertyfx.ID.Key(): []string{"propertyfx"},
|
||||||
}
|
}
|
||||||
|
|
||||||
genesisBytes := Genesis(networkID)
|
genesisBytes := Genesis(networkID)
|
||||||
|
@ -353,6 +355,7 @@ func Genesis(networkID uint32) []byte {
|
||||||
FxIDs: []ids.ID{
|
FxIDs: []ids.ID{
|
||||||
secp256k1fx.ID,
|
secp256k1fx.ID,
|
||||||
nftfx.ID,
|
nftfx.ID,
|
||||||
|
propertyfx.ID,
|
||||||
},
|
},
|
||||||
Name: "X-Chain",
|
Name: "X-Chain",
|
||||||
},
|
},
|
||||||
|
|
|
@ -41,6 +41,7 @@ import (
|
||||||
"github.com/ava-labs/gecko/vms/evm"
|
"github.com/ava-labs/gecko/vms/evm"
|
||||||
"github.com/ava-labs/gecko/vms/nftfx"
|
"github.com/ava-labs/gecko/vms/nftfx"
|
||||||
"github.com/ava-labs/gecko/vms/platformvm"
|
"github.com/ava-labs/gecko/vms/platformvm"
|
||||||
|
"github.com/ava-labs/gecko/vms/propertyfx"
|
||||||
"github.com/ava-labs/gecko/vms/secp256k1fx"
|
"github.com/ava-labs/gecko/vms/secp256k1fx"
|
||||||
"github.com/ava-labs/gecko/vms/spchainvm"
|
"github.com/ava-labs/gecko/vms/spchainvm"
|
||||||
"github.com/ava-labs/gecko/vms/spdagvm"
|
"github.com/ava-labs/gecko/vms/spdagvm"
|
||||||
|
@ -337,6 +338,7 @@ func (n *Node) initVMManager() {
|
||||||
n.vmManager.RegisterVMFactory(timestampvm.ID, ×tampvm.Factory{})
|
n.vmManager.RegisterVMFactory(timestampvm.ID, ×tampvm.Factory{})
|
||||||
n.vmManager.RegisterVMFactory(secp256k1fx.ID, &secp256k1fx.Factory{})
|
n.vmManager.RegisterVMFactory(secp256k1fx.ID, &secp256k1fx.Factory{})
|
||||||
n.vmManager.RegisterVMFactory(nftfx.ID, &nftfx.Factory{})
|
n.vmManager.RegisterVMFactory(nftfx.ID, &nftfx.Factory{})
|
||||||
|
n.vmManager.RegisterVMFactory(propertyfx.ID, &propertyfx.Factory{})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the EventDispatcher used for hooking events
|
// Create the EventDispatcher used for hooking events
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
package propertyfx
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/ava-labs/gecko/vms/components/verify"
|
||||||
|
"github.com/ava-labs/gecko/vms/secp256k1fx"
|
||||||
|
)
|
||||||
|
|
||||||
|
// BurnOperation ...
|
||||||
|
type BurnOperation struct {
|
||||||
|
secp256k1fx.Input `serialize:"true"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Outs ...
|
||||||
|
func (op *BurnOperation) Outs() []verify.Verifiable { return nil }
|
|
@ -0,0 +1,23 @@
|
||||||
|
package propertyfx
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/ava-labs/gecko/vms/secp256k1fx"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestBurnOperationInvalid(t *testing.T) {
|
||||||
|
op := BurnOperation{Input: secp256k1fx.Input{
|
||||||
|
SigIndices: []uint32{1, 0},
|
||||||
|
}}
|
||||||
|
if err := op.Verify(); err == nil {
|
||||||
|
t.Fatalf("operation should have failed verification")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBurnOperationNumberOfOutput(t *testing.T) {
|
||||||
|
op := BurnOperation{}
|
||||||
|
if outs := op.Outs(); len(outs) != 0 {
|
||||||
|
t.Fatalf("wrong number of outputs")
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
package propertyfx
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/ava-labs/gecko/vms/secp256k1fx"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Credential ...
|
||||||
|
type Credential struct {
|
||||||
|
secp256k1fx.Credential `serialize:"true"`
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
package propertyfx
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/ava-labs/gecko/ids"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ID that this Fx uses when labeled
|
||||||
|
var (
|
||||||
|
ID = ids.NewID([32]byte{'p', 'r', 'o', 'p', 'e', 'r', 't', 'y', 'f', 'x'})
|
||||||
|
)
|
||||||
|
|
||||||
|
// Factory ...
|
||||||
|
type Factory struct{}
|
||||||
|
|
||||||
|
// New ...
|
||||||
|
func (f *Factory) New() interface{} { return &Fx{} }
|
|
@ -0,0 +1,12 @@
|
||||||
|
package propertyfx
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestFactory(t *testing.T) {
|
||||||
|
factory := Factory{}
|
||||||
|
if fx := factory.New(); fx == nil {
|
||||||
|
t.Fatalf("Factory.New returned nil")
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,109 @@
|
||||||
|
package propertyfx
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/ava-labs/gecko/utils/wrappers"
|
||||||
|
"github.com/ava-labs/gecko/vms/components/verify"
|
||||||
|
"github.com/ava-labs/gecko/vms/secp256k1fx"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
errWrongTxType = errors.New("wrong tx type")
|
||||||
|
errWrongUTXOType = errors.New("wrong utxo type")
|
||||||
|
errWrongOperationType = errors.New("wrong operation type")
|
||||||
|
errWrongCredentialType = errors.New("wrong credential type")
|
||||||
|
|
||||||
|
errNoUTXOs = errors.New("an operation must consume at least one UTXO")
|
||||||
|
errWrongNumberOfUTXOs = errors.New("wrong number of UTXOs for the operation")
|
||||||
|
errWrongNumberOfCreds = errors.New("wrong number of credentials for the operation")
|
||||||
|
|
||||||
|
errWrongMintOutput = errors.New("wrong mint output provided")
|
||||||
|
|
||||||
|
errCantTransfer = errors.New("cant transfer with this fx")
|
||||||
|
)
|
||||||
|
|
||||||
|
// Fx ...
|
||||||
|
type Fx struct{ secp256k1fx.Fx }
|
||||||
|
|
||||||
|
// Initialize ...
|
||||||
|
func (fx *Fx) Initialize(vmIntf interface{}) error {
|
||||||
|
if err := fx.InitializeVM(vmIntf); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
log := fx.VM.Logger()
|
||||||
|
log.Debug("Initializing nft fx")
|
||||||
|
|
||||||
|
c := fx.VM.Codec()
|
||||||
|
errs := wrappers.Errs{}
|
||||||
|
errs.Add(
|
||||||
|
c.RegisterType(&MintOutput{}),
|
||||||
|
c.RegisterType(&OwnedOutput{}),
|
||||||
|
c.RegisterType(&MintOperation{}),
|
||||||
|
c.RegisterType(&BurnOperation{}),
|
||||||
|
c.RegisterType(&Credential{}),
|
||||||
|
)
|
||||||
|
return errs.Err
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyOperation ...
|
||||||
|
func (fx *Fx) VerifyOperation(txIntf, opIntf, credIntf interface{}, utxosIntf []interface{}) error {
|
||||||
|
tx, ok := txIntf.(secp256k1fx.Tx)
|
||||||
|
switch {
|
||||||
|
case !ok:
|
||||||
|
return errWrongTxType
|
||||||
|
case len(utxosIntf) != 1:
|
||||||
|
return errWrongNumberOfUTXOs
|
||||||
|
}
|
||||||
|
|
||||||
|
cred, ok := credIntf.(*Credential)
|
||||||
|
if !ok {
|
||||||
|
return errWrongCredentialType
|
||||||
|
}
|
||||||
|
|
||||||
|
switch op := opIntf.(type) {
|
||||||
|
case *MintOperation:
|
||||||
|
return fx.VerifyMintOperation(tx, op, cred, utxosIntf[0])
|
||||||
|
case *BurnOperation:
|
||||||
|
return fx.VerifyTransferOperation(tx, op, cred, utxosIntf[0])
|
||||||
|
default:
|
||||||
|
return errWrongOperationType
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyMintOperation ...
|
||||||
|
func (fx *Fx) VerifyMintOperation(tx secp256k1fx.Tx, op *MintOperation, cred *Credential, utxoIntf interface{}) error {
|
||||||
|
out, ok := utxoIntf.(*MintOutput)
|
||||||
|
if !ok {
|
||||||
|
return errWrongUTXOType
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := verify.All(op, cred, out); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case !out.OutputOwners.Equals(&op.MintOutput.OutputOwners):
|
||||||
|
return errWrongMintOutput
|
||||||
|
default:
|
||||||
|
return fx.Fx.VerifyCredentials(tx, &op.MintInput, &cred.Credential, &out.OutputOwners)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyTransferOperation ...
|
||||||
|
func (fx *Fx) VerifyTransferOperation(tx secp256k1fx.Tx, op *BurnOperation, cred *Credential, utxoIntf interface{}) error {
|
||||||
|
out, ok := utxoIntf.(*OwnedOutput)
|
||||||
|
if !ok {
|
||||||
|
return errWrongUTXOType
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := verify.All(op, cred, out); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return fx.VerifyCredentials(tx, &op.Input, &cred.Credential, &out.OutputOwners)
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyTransfer ...
|
||||||
|
func (fx *Fx) VerifyTransfer(_, _, _, _ interface{}) error { return errCantTransfer }
|
|
@ -0,0 +1,473 @@
|
||||||
|
package propertyfx
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/ava-labs/gecko/ids"
|
||||||
|
"github.com/ava-labs/gecko/utils/crypto"
|
||||||
|
"github.com/ava-labs/gecko/utils/hashing"
|
||||||
|
"github.com/ava-labs/gecko/utils/logging"
|
||||||
|
"github.com/ava-labs/gecko/utils/timer"
|
||||||
|
"github.com/ava-labs/gecko/vms/components/codec"
|
||||||
|
"github.com/ava-labs/gecko/vms/secp256k1fx"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
txBytes = []byte{0, 1, 2, 3, 4, 5}
|
||||||
|
sigBytes = [crypto.SECP256K1RSigLen]byte{
|
||||||
|
0x0e, 0x33, 0x4e, 0xbc, 0x67, 0xa7, 0x3f, 0xe8,
|
||||||
|
0x24, 0x33, 0xac, 0xa3, 0x47, 0x88, 0xa6, 0x3d,
|
||||||
|
0x58, 0xe5, 0x8e, 0xf0, 0x3a, 0xd5, 0x84, 0xf1,
|
||||||
|
0xbc, 0xa3, 0xb2, 0xd2, 0x5d, 0x51, 0xd6, 0x9b,
|
||||||
|
0x0f, 0x28, 0x5d, 0xcd, 0x3f, 0x71, 0x17, 0x0a,
|
||||||
|
0xf9, 0xbf, 0x2d, 0xb1, 0x10, 0x26, 0x5c, 0xe9,
|
||||||
|
0xdc, 0xc3, 0x9d, 0x7a, 0x01, 0x50, 0x9d, 0xe8,
|
||||||
|
0x35, 0xbd, 0xcb, 0x29, 0x3a, 0xd1, 0x49, 0x32,
|
||||||
|
0x00,
|
||||||
|
}
|
||||||
|
addrBytes = [hashing.AddrLen]byte{
|
||||||
|
0x01, 0x5c, 0xce, 0x6c, 0x55, 0xd6, 0xb5, 0x09,
|
||||||
|
0x84, 0x5c, 0x8c, 0x4e, 0x30, 0xbe, 0xd9, 0x8d,
|
||||||
|
0x39, 0x1a, 0xe7, 0xf0,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestFxInitialize(t *testing.T) {
|
||||||
|
vm := secp256k1fx.TestVM{
|
||||||
|
CLK: new(timer.Clock),
|
||||||
|
Code: codec.NewDefault(),
|
||||||
|
Log: logging.NoLog{},
|
||||||
|
}
|
||||||
|
fx := Fx{}
|
||||||
|
err := fx.Initialize(&vm)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFxInitializeInvalid(t *testing.T) {
|
||||||
|
fx := Fx{}
|
||||||
|
err := fx.Initialize(nil)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatalf("Should have returned an error")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFxVerifyMintOperation(t *testing.T) {
|
||||||
|
vm := secp256k1fx.TestVM{
|
||||||
|
CLK: new(timer.Clock),
|
||||||
|
Code: codec.NewDefault(),
|
||||||
|
Log: logging.NoLog{},
|
||||||
|
}
|
||||||
|
date := time.Date(2019, time.January, 19, 16, 25, 17, 3, time.UTC)
|
||||||
|
vm.CLK.Set(date)
|
||||||
|
|
||||||
|
fx := Fx{}
|
||||||
|
if err := fx.Initialize(&vm); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
tx := &secp256k1fx.TestTx{
|
||||||
|
Bytes: txBytes,
|
||||||
|
}
|
||||||
|
cred := &Credential{Credential: secp256k1fx.Credential{
|
||||||
|
Sigs: [][crypto.SECP256K1RSigLen]byte{
|
||||||
|
sigBytes,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
utxo := &MintOutput{OutputOwners: secp256k1fx.OutputOwners{
|
||||||
|
Threshold: 1,
|
||||||
|
Addrs: []ids.ShortID{
|
||||||
|
ids.NewShortID(addrBytes),
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
op := &MintOperation{
|
||||||
|
MintInput: secp256k1fx.Input{
|
||||||
|
SigIndices: []uint32{0},
|
||||||
|
},
|
||||||
|
MintOutput: MintOutput{OutputOwners: secp256k1fx.OutputOwners{
|
||||||
|
Threshold: 1,
|
||||||
|
Addrs: []ids.ShortID{
|
||||||
|
ids.NewShortID(addrBytes),
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
}
|
||||||
|
|
||||||
|
utxos := []interface{}{utxo}
|
||||||
|
if err := fx.VerifyOperation(tx, op, cred, utxos); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFxVerifyMintOperationWrongTx(t *testing.T) {
|
||||||
|
vm := secp256k1fx.TestVM{
|
||||||
|
CLK: new(timer.Clock),
|
||||||
|
Code: codec.NewDefault(),
|
||||||
|
Log: logging.NoLog{},
|
||||||
|
}
|
||||||
|
date := time.Date(2019, time.January, 19, 16, 25, 17, 3, time.UTC)
|
||||||
|
vm.CLK.Set(date)
|
||||||
|
|
||||||
|
fx := Fx{}
|
||||||
|
if err := fx.Initialize(&vm); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
cred := &Credential{Credential: secp256k1fx.Credential{
|
||||||
|
Sigs: [][crypto.SECP256K1RSigLen]byte{
|
||||||
|
sigBytes,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
utxo := &MintOutput{OutputOwners: secp256k1fx.OutputOwners{
|
||||||
|
Threshold: 1,
|
||||||
|
Addrs: []ids.ShortID{
|
||||||
|
ids.NewShortID(addrBytes),
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
op := &MintOperation{
|
||||||
|
MintInput: secp256k1fx.Input{
|
||||||
|
SigIndices: []uint32{0},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
utxos := []interface{}{utxo}
|
||||||
|
if err := fx.VerifyOperation(nil, op, cred, utxos); err == nil {
|
||||||
|
t.Fatalf("VerifyOperation should have errored due to an invalid tx")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFxVerifyMintOperationWrongNumberUTXOs(t *testing.T) {
|
||||||
|
vm := secp256k1fx.TestVM{
|
||||||
|
CLK: new(timer.Clock),
|
||||||
|
Code: codec.NewDefault(),
|
||||||
|
Log: logging.NoLog{},
|
||||||
|
}
|
||||||
|
date := time.Date(2019, time.January, 19, 16, 25, 17, 3, time.UTC)
|
||||||
|
vm.CLK.Set(date)
|
||||||
|
|
||||||
|
fx := Fx{}
|
||||||
|
if err := fx.Initialize(&vm); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
tx := &secp256k1fx.TestTx{
|
||||||
|
Bytes: txBytes,
|
||||||
|
}
|
||||||
|
cred := &Credential{Credential: secp256k1fx.Credential{
|
||||||
|
Sigs: [][crypto.SECP256K1RSigLen]byte{
|
||||||
|
sigBytes,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
op := &MintOperation{
|
||||||
|
MintInput: secp256k1fx.Input{
|
||||||
|
SigIndices: []uint32{0},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
utxos := []interface{}{}
|
||||||
|
if err := fx.VerifyOperation(tx, op, cred, utxos); err == nil {
|
||||||
|
t.Fatalf("VerifyOperation should have errored due to not enough utxos")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFxVerifyMintOperationWrongCredential(t *testing.T) {
|
||||||
|
vm := secp256k1fx.TestVM{
|
||||||
|
CLK: new(timer.Clock),
|
||||||
|
Code: codec.NewDefault(),
|
||||||
|
Log: logging.NoLog{},
|
||||||
|
}
|
||||||
|
date := time.Date(2019, time.January, 19, 16, 25, 17, 3, time.UTC)
|
||||||
|
vm.CLK.Set(date)
|
||||||
|
|
||||||
|
fx := Fx{}
|
||||||
|
if err := fx.Initialize(&vm); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
tx := &secp256k1fx.TestTx{
|
||||||
|
Bytes: txBytes,
|
||||||
|
}
|
||||||
|
utxo := &MintOutput{OutputOwners: secp256k1fx.OutputOwners{
|
||||||
|
Threshold: 1,
|
||||||
|
Addrs: []ids.ShortID{
|
||||||
|
ids.NewShortID(addrBytes),
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
op := &MintOperation{
|
||||||
|
MintInput: secp256k1fx.Input{
|
||||||
|
SigIndices: []uint32{0},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
utxos := []interface{}{utxo}
|
||||||
|
if err := fx.VerifyOperation(tx, op, nil, utxos); err == nil {
|
||||||
|
t.Fatalf("VerifyOperation should have errored due to a bad credential")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFxVerifyMintOperationInvalidUTXO(t *testing.T) {
|
||||||
|
vm := secp256k1fx.TestVM{
|
||||||
|
CLK: new(timer.Clock),
|
||||||
|
Code: codec.NewDefault(),
|
||||||
|
Log: logging.NoLog{},
|
||||||
|
}
|
||||||
|
date := time.Date(2019, time.January, 19, 16, 25, 17, 3, time.UTC)
|
||||||
|
vm.CLK.Set(date)
|
||||||
|
|
||||||
|
fx := Fx{}
|
||||||
|
if err := fx.Initialize(&vm); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
tx := &secp256k1fx.TestTx{
|
||||||
|
Bytes: txBytes,
|
||||||
|
}
|
||||||
|
cred := &Credential{Credential: secp256k1fx.Credential{
|
||||||
|
Sigs: [][crypto.SECP256K1RSigLen]byte{
|
||||||
|
sigBytes,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
op := &MintOperation{
|
||||||
|
MintInput: secp256k1fx.Input{
|
||||||
|
SigIndices: []uint32{0},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
utxos := []interface{}{nil}
|
||||||
|
if err := fx.VerifyOperation(tx, op, cred, utxos); err == nil {
|
||||||
|
t.Fatalf("VerifyOperation should have errored due to an invalid utxo")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFxVerifyMintOperationFailingVerification(t *testing.T) {
|
||||||
|
vm := secp256k1fx.TestVM{
|
||||||
|
CLK: new(timer.Clock),
|
||||||
|
Code: codec.NewDefault(),
|
||||||
|
Log: logging.NoLog{},
|
||||||
|
}
|
||||||
|
date := time.Date(2019, time.January, 19, 16, 25, 17, 3, time.UTC)
|
||||||
|
vm.CLK.Set(date)
|
||||||
|
|
||||||
|
fx := Fx{}
|
||||||
|
if err := fx.Initialize(&vm); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
tx := &secp256k1fx.TestTx{
|
||||||
|
Bytes: txBytes,
|
||||||
|
}
|
||||||
|
cred := &Credential{Credential: secp256k1fx.Credential{
|
||||||
|
Sigs: [][crypto.SECP256K1RSigLen]byte{
|
||||||
|
sigBytes,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
utxo := &MintOutput{OutputOwners: secp256k1fx.OutputOwners{
|
||||||
|
Threshold: 1,
|
||||||
|
Addrs: []ids.ShortID{
|
||||||
|
ids.NewShortID(addrBytes),
|
||||||
|
ids.ShortEmpty,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
op := &MintOperation{
|
||||||
|
MintInput: secp256k1fx.Input{
|
||||||
|
SigIndices: []uint32{0},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
utxos := []interface{}{utxo}
|
||||||
|
if err := fx.VerifyOperation(tx, op, cred, utxos); err == nil {
|
||||||
|
t.Fatalf("VerifyOperation should have errored due to an invalid utxo output")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFxVerifyMintOperationInvalidGroupID(t *testing.T) {
|
||||||
|
vm := secp256k1fx.TestVM{
|
||||||
|
CLK: new(timer.Clock),
|
||||||
|
Code: codec.NewDefault(),
|
||||||
|
Log: logging.NoLog{},
|
||||||
|
}
|
||||||
|
date := time.Date(2019, time.January, 19, 16, 25, 17, 3, time.UTC)
|
||||||
|
vm.CLK.Set(date)
|
||||||
|
|
||||||
|
fx := Fx{}
|
||||||
|
if err := fx.Initialize(&vm); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
tx := &secp256k1fx.TestTx{
|
||||||
|
Bytes: txBytes,
|
||||||
|
}
|
||||||
|
cred := &Credential{Credential: secp256k1fx.Credential{
|
||||||
|
Sigs: [][crypto.SECP256K1RSigLen]byte{
|
||||||
|
sigBytes,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
utxo := &MintOutput{OutputOwners: secp256k1fx.OutputOwners{
|
||||||
|
Threshold: 1,
|
||||||
|
Addrs: []ids.ShortID{
|
||||||
|
ids.NewShortID(addrBytes),
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
op := &MintOperation{
|
||||||
|
MintInput: secp256k1fx.Input{
|
||||||
|
SigIndices: []uint32{0},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
utxos := []interface{}{utxo}
|
||||||
|
if err := fx.VerifyOperation(tx, op, cred, utxos); err == nil {
|
||||||
|
t.Fatalf("VerifyOperation should have errored due to an invalid mint output")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFxVerifyTransferOperation(t *testing.T) {
|
||||||
|
vm := secp256k1fx.TestVM{
|
||||||
|
CLK: new(timer.Clock),
|
||||||
|
Code: codec.NewDefault(),
|
||||||
|
Log: logging.NoLog{},
|
||||||
|
}
|
||||||
|
date := time.Date(2019, time.January, 19, 16, 25, 17, 3, time.UTC)
|
||||||
|
vm.CLK.Set(date)
|
||||||
|
|
||||||
|
fx := Fx{}
|
||||||
|
if err := fx.Initialize(&vm); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
tx := &secp256k1fx.TestTx{
|
||||||
|
Bytes: txBytes,
|
||||||
|
}
|
||||||
|
cred := &Credential{Credential: secp256k1fx.Credential{
|
||||||
|
Sigs: [][crypto.SECP256K1RSigLen]byte{
|
||||||
|
sigBytes,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
utxo := &OwnedOutput{OutputOwners: secp256k1fx.OutputOwners{
|
||||||
|
Threshold: 1,
|
||||||
|
Addrs: []ids.ShortID{
|
||||||
|
ids.NewShortID(addrBytes),
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
op := &BurnOperation{Input: secp256k1fx.Input{
|
||||||
|
SigIndices: []uint32{0},
|
||||||
|
}}
|
||||||
|
|
||||||
|
utxos := []interface{}{utxo}
|
||||||
|
if err := fx.VerifyOperation(tx, op, cred, utxos); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFxVerifyTransferOperationWrongUTXO(t *testing.T) {
|
||||||
|
vm := secp256k1fx.TestVM{
|
||||||
|
CLK: new(timer.Clock),
|
||||||
|
Code: codec.NewDefault(),
|
||||||
|
Log: logging.NoLog{},
|
||||||
|
}
|
||||||
|
date := time.Date(2019, time.January, 19, 16, 25, 17, 3, time.UTC)
|
||||||
|
vm.CLK.Set(date)
|
||||||
|
|
||||||
|
fx := Fx{}
|
||||||
|
if err := fx.Initialize(&vm); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
tx := &secp256k1fx.TestTx{
|
||||||
|
Bytes: txBytes,
|
||||||
|
}
|
||||||
|
cred := &Credential{Credential: secp256k1fx.Credential{
|
||||||
|
Sigs: [][crypto.SECP256K1RSigLen]byte{
|
||||||
|
sigBytes,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
op := &BurnOperation{Input: secp256k1fx.Input{
|
||||||
|
SigIndices: []uint32{0},
|
||||||
|
}}
|
||||||
|
|
||||||
|
utxos := []interface{}{nil}
|
||||||
|
if err := fx.VerifyOperation(tx, op, cred, utxos); err == nil {
|
||||||
|
t.Fatalf("VerifyOperation should have errored due to an invalid utxo")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFxVerifyTransferOperationFailedVerify(t *testing.T) {
|
||||||
|
|
||||||
|
vm := secp256k1fx.TestVM{
|
||||||
|
CLK: new(timer.Clock),
|
||||||
|
Code: codec.NewDefault(),
|
||||||
|
Log: logging.NoLog{},
|
||||||
|
}
|
||||||
|
date := time.Date(2019, time.January, 19, 16, 25, 17, 3, time.UTC)
|
||||||
|
vm.CLK.Set(date)
|
||||||
|
|
||||||
|
fx := Fx{}
|
||||||
|
if err := fx.Initialize(&vm); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
tx := &secp256k1fx.TestTx{
|
||||||
|
Bytes: txBytes,
|
||||||
|
}
|
||||||
|
cred := &Credential{Credential: secp256k1fx.Credential{
|
||||||
|
Sigs: [][crypto.SECP256K1RSigLen]byte{
|
||||||
|
sigBytes,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
utxo := &OwnedOutput{OutputOwners: secp256k1fx.OutputOwners{
|
||||||
|
Threshold: 1,
|
||||||
|
Addrs: []ids.ShortID{
|
||||||
|
ids.NewShortID(addrBytes),
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
op := &BurnOperation{Input: secp256k1fx.Input{
|
||||||
|
SigIndices: []uint32{1, 0},
|
||||||
|
}}
|
||||||
|
|
||||||
|
utxos := []interface{}{utxo}
|
||||||
|
if err := fx.VerifyOperation(tx, op, cred, utxos); err == nil {
|
||||||
|
t.Fatalf("VerifyOperation should have errored due to an invalid utxo output")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFxVerifyOperationUnknownOperation(t *testing.T) {
|
||||||
|
vm := secp256k1fx.TestVM{
|
||||||
|
CLK: new(timer.Clock),
|
||||||
|
Code: codec.NewDefault(),
|
||||||
|
Log: logging.NoLog{},
|
||||||
|
}
|
||||||
|
date := time.Date(2019, time.January, 19, 16, 25, 17, 3, time.UTC)
|
||||||
|
vm.CLK.Set(date)
|
||||||
|
|
||||||
|
fx := Fx{}
|
||||||
|
if err := fx.Initialize(&vm); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
tx := &secp256k1fx.TestTx{
|
||||||
|
Bytes: txBytes,
|
||||||
|
}
|
||||||
|
cred := &Credential{Credential: secp256k1fx.Credential{
|
||||||
|
Sigs: [][crypto.SECP256K1RSigLen]byte{
|
||||||
|
sigBytes,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
utxo := &OwnedOutput{OutputOwners: secp256k1fx.OutputOwners{
|
||||||
|
Threshold: 1,
|
||||||
|
Addrs: []ids.ShortID{
|
||||||
|
ids.NewShortID(addrBytes),
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
|
||||||
|
utxos := []interface{}{utxo}
|
||||||
|
if err := fx.VerifyOperation(tx, nil, cred, utxos); err == nil {
|
||||||
|
t.Fatalf("VerifyOperation should have errored due to an unknown operation")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFxVerifyTransfer(t *testing.T) {
|
||||||
|
vm := secp256k1fx.TestVM{
|
||||||
|
CLK: new(timer.Clock),
|
||||||
|
Code: codec.NewDefault(),
|
||||||
|
Log: logging.NoLog{},
|
||||||
|
}
|
||||||
|
date := time.Date(2019, time.January, 19, 16, 25, 17, 3, time.UTC)
|
||||||
|
vm.CLK.Set(date)
|
||||||
|
|
||||||
|
fx := Fx{}
|
||||||
|
if err := fx.Initialize(&vm); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if err := fx.VerifyTransfer(nil, nil, nil, nil); err == nil {
|
||||||
|
t.Fatalf("this Fx doesn't support transfers")
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
package propertyfx
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/ava-labs/gecko/vms/components/verify"
|
||||||
|
"github.com/ava-labs/gecko/vms/secp256k1fx"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
errNilMintOperation = errors.New("nil mint operation")
|
||||||
|
)
|
||||||
|
|
||||||
|
// MintOperation ...
|
||||||
|
type MintOperation struct {
|
||||||
|
MintInput secp256k1fx.Input `serialize:"true"`
|
||||||
|
MintOutput MintOutput `serialize:"true"`
|
||||||
|
OwnedOutput OwnedOutput `serialize:"true"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Outs ...
|
||||||
|
func (op *MintOperation) Outs() []verify.Verifiable {
|
||||||
|
return []verify.Verifiable{
|
||||||
|
&op.MintOutput,
|
||||||
|
&op.OwnedOutput,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify ...
|
||||||
|
func (op *MintOperation) Verify() error {
|
||||||
|
switch {
|
||||||
|
case op == nil:
|
||||||
|
return errNilMintOperation
|
||||||
|
default:
|
||||||
|
return verify.All(&op.MintInput, &op.MintOutput, &op.OwnedOutput)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
package propertyfx
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/ava-labs/gecko/vms/secp256k1fx"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestMintOperationVerifyNil(t *testing.T) {
|
||||||
|
op := (*MintOperation)(nil)
|
||||||
|
if err := op.Verify(); err == nil {
|
||||||
|
t.Fatalf("nil operation should have failed verification")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMintOperationVerifyInvalidOutput(t *testing.T) {
|
||||||
|
op := MintOperation{
|
||||||
|
OwnedOutput: OwnedOutput{
|
||||||
|
OutputOwners: secp256k1fx.OutputOwners{
|
||||||
|
Threshold: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
if err := op.Verify(); err == nil {
|
||||||
|
t.Fatalf("operation should have failed verification")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMintOperationOuts(t *testing.T) {
|
||||||
|
op := MintOperation{}
|
||||||
|
if outs := op.Outs(); len(outs) != 2 {
|
||||||
|
t.Fatalf("Wrong number of outputs returned")
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
package propertyfx
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/ava-labs/gecko/vms/secp256k1fx"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MintOutput ...
|
||||||
|
type MintOutput struct {
|
||||||
|
secp256k1fx.OutputOwners `serialize:"true"`
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
package propertyfx
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/ava-labs/gecko/vms/secp256k1fx"
|
||||||
|
)
|
||||||
|
|
||||||
|
// OwnedOutput ...
|
||||||
|
type OwnedOutput struct {
|
||||||
|
secp256k1fx.OutputOwners `serialize:"true"`
|
||||||
|
}
|
Loading…
Reference in New Issue