Implemented NFTs

This commit is contained in:
StephenButtolph 2020-03-30 16:23:06 -04:00
parent ffcdfafaf6
commit a2c0ad56f7
19 changed files with 1423 additions and 329 deletions

View File

@ -8,19 +8,28 @@ package genesis
import (
"fmt"
"math"
"math/big"
"regexp"
"strconv"
"strings"
"time"
"github.com/ava-labs/coreth/core"
"github.com/ava-labs/gecko/ids"
"github.com/ava-labs/gecko/utils/formatting"
"github.com/ava-labs/gecko/utils/json"
"github.com/ava-labs/gecko/utils/units"
"github.com/ava-labs/gecko/vms/avm"
"github.com/ava-labs/gecko/vms/components/codec"
"github.com/ava-labs/gecko/vms/evm"
"github.com/ava-labs/gecko/vms/nftfx"
"github.com/ava-labs/gecko/vms/platformvm"
"github.com/ava-labs/gecko/vms/secp256k1fx"
"github.com/ava-labs/gecko/vms/spchainvm"
"github.com/ava-labs/gecko/vms/spdagvm"
"github.com/ava-labs/gecko/vms/timestampvm"
"github.com/ava-labs/go-ethereum/common"
"github.com/ava-labs/go-ethereum/params"
)
// Note that since an AVA network has exactly one Platform Chain,
@ -149,6 +158,8 @@ func Aliases(networkID uint32) (generalAliases map[string][]string, chainAliases
spdagvm.ID.Key(): []string{"spdag"},
spchainvm.ID.Key(): []string{"spchain"},
timestampvm.ID.Key(): []string{"timestamp"},
secp256k1fx.ID.Key(): []string{"secp256k1fx"},
nftfx.ID.Key(): []string{"nftfx"},
}
genesisBytes := Genesis(networkID)
@ -187,318 +198,195 @@ func Genesis(networkID uint32) []byte {
panic("unknown network ID provided")
}
return []byte{
0x00, 0x00, 0x00, 0x01, 0x3c, 0xb7, 0xd3, 0x84,
0x2e, 0x8c, 0xee, 0x6a, 0x0e, 0xbd, 0x09, 0xf1,
0xfe, 0x88, 0x4f, 0x68, 0x61, 0xe1, 0xb2, 0x9c,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x12, 0x30, 0x9c, 0xe5, 0x40, 0x00,
0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
0x0b, 0xde, 0x31, 0xb4, 0xd8, 0xb2, 0x29, 0x91,
0xd5, 0x1a, 0xa6, 0xaa, 0x1f, 0xc7, 0x33, 0xf2,
0x3a, 0x85, 0x1a, 0x8c, 0x94, 0x00, 0x00, 0x12,
0x30, 0x9c, 0xe5, 0x40, 0x00, 0x00, 0x00, 0x00,
0x00, 0x5d, 0xbb, 0x75, 0x80, 0x00, 0x00, 0x00,
0x00, 0x5f, 0x9c, 0xa9, 0x00, 0x00, 0x00, 0x30,
0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x3c, 0xb7, 0xd3, 0x84, 0x2e, 0x8c, 0xee,
0x6a, 0x0e, 0xbd, 0x09, 0xf1, 0xfe, 0x88, 0x4f,
0x68, 0x61, 0xe1, 0xb2, 0x9c, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0xaa, 0x18,
0xd3, 0x99, 0x1c, 0xf6, 0x37, 0xaa, 0x6c, 0x16,
0x2f, 0x5e, 0x95, 0xcf, 0x16, 0x3f, 0x69, 0xcd,
0x82, 0x91, 0x00, 0x00, 0x12, 0x30, 0x9c, 0xe5,
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5d, 0xbb,
0x75, 0x80, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x9c,
0xa9, 0x00, 0x00, 0x00, 0x30, 0x39, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0xb7,
0xd3, 0x84, 0x2e, 0x8c, 0xee, 0x6a, 0x0e, 0xbd,
0x09, 0xf1, 0xfe, 0x88, 0x4f, 0x68, 0x61, 0xe1,
0xb2, 0x9c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x0b, 0xe9, 0x09, 0x4f, 0x73, 0x69,
0x80, 0x02, 0xfd, 0x52, 0xc9, 0x08, 0x19, 0xb4,
0x57, 0xb9, 0xfb, 0xc8, 0x66, 0xab, 0x80, 0x00,
0x00, 0x12, 0x30, 0x9c, 0xe5, 0x40, 0x00, 0x00,
0x00, 0x00, 0x00, 0x5d, 0xbb, 0x75, 0x80, 0x00,
0x00, 0x00, 0x00, 0x5f, 0x9c, 0xa9, 0x00, 0x00,
0x00, 0x30, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x3c, 0xb7, 0xd3, 0x84, 0x2e,
0x8c, 0xee, 0x6a, 0x0e, 0xbd, 0x09, 0xf1, 0xfe,
0x88, 0x4f, 0x68, 0x61, 0xe1, 0xb2, 0x9c, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b,
0x47, 0x9f, 0x66, 0xc8, 0xbe, 0x89, 0x58, 0x30,
0x54, 0x7e, 0x70, 0xb4, 0xb2, 0x98, 0xca, 0xfd,
0x43, 0x3d, 0xba, 0x6e, 0x00, 0x00, 0x12, 0x30,
0x9c, 0xe5, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
0x5d, 0xbb, 0x75, 0x80, 0x00, 0x00, 0x00, 0x00,
0x5f, 0x9c, 0xa9, 0x00, 0x00, 0x00, 0x30, 0x39,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x3c, 0xb7, 0xd3, 0x84, 0x2e, 0x8c, 0xee, 0x6a,
0x0e, 0xbd, 0x09, 0xf1, 0xfe, 0x88, 0x4f, 0x68,
0x61, 0xe1, 0xb2, 0x9c, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x0b, 0xf2, 0x9b, 0xce,
0x5f, 0x34, 0xa7, 0x43, 0x01, 0xeb, 0x0d, 0xe7,
0x16, 0xd5, 0x19, 0x4e, 0x4a, 0x4a, 0xea, 0x5d,
0x7a, 0x00, 0x00, 0x12, 0x30, 0x9c, 0xe5, 0x40,
0x00, 0x00, 0x00, 0x00, 0x00, 0x5d, 0xbb, 0x75,
0x80, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x9c, 0xa9,
0x00, 0x00, 0x00, 0x30, 0x39, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0xb7, 0xd3,
0x84, 0x2e, 0x8c, 0xee, 0x6a, 0x0e, 0xbd, 0x09,
0xf1, 0xfe, 0x88, 0x4f, 0x68, 0x61, 0xe1, 0xb2,
0x9c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x05, 0x00, 0x00, 0x30, 0x39, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
0x58, 0x2d, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x61,
0x76, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x01, 0x73, 0x65, 0x63, 0x70, 0x32,
0x35, 0x36, 0x6b, 0x31, 0x66, 0x78, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00,
0x00, 0x00, 0x01, 0x00, 0x03, 0x41, 0x56, 0x41,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x41, 0x56,
0x41, 0x00, 0x03, 0x41, 0x56, 0x41, 0x09, 0x00,
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x07, 0x00,
0x9f, 0xdf, 0x42, 0xf6, 0xe4, 0x80, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x3c,
0xb7, 0xd3, 0x84, 0x2e, 0x8c, 0xee, 0x6a, 0x0e,
0xbd, 0x09, 0xf1, 0xfe, 0x88, 0x4f, 0x68, 0x61,
0xe1, 0xb2, 0x9c, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x39,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x07, 0x43, 0x2d, 0x43, 0x68, 0x61, 0x69,
0x6e, 0x65, 0x76, 0x6d, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
0xc9, 0x7b, 0x22, 0x63, 0x6f, 0x6e, 0x66, 0x69,
0x67, 0x22, 0x3a, 0x7b, 0x22, 0x63, 0x68, 0x61,
0x69, 0x6e, 0x49, 0x64, 0x22, 0x3a, 0x34, 0x33,
0x31, 0x31, 0x30, 0x2c, 0x22, 0x68, 0x6f, 0x6d,
0x65, 0x73, 0x74, 0x65, 0x61, 0x64, 0x42, 0x6c,
0x6f, 0x63, 0x6b, 0x22, 0x3a, 0x30, 0x2c, 0x22,
0x64, 0x61, 0x6f, 0x46, 0x6f, 0x72, 0x6b, 0x42,
0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x3a, 0x30, 0x2c,
0x22, 0x64, 0x61, 0x6f, 0x46, 0x6f, 0x72, 0x6b,
0x53, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x22,
0x3a, 0x74, 0x72, 0x75, 0x65, 0x2c, 0x22, 0x65,
0x69, 0x70, 0x31, 0x35, 0x30, 0x42, 0x6c, 0x6f,
0x63, 0x6b, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x65,
0x69, 0x70, 0x31, 0x35, 0x30, 0x48, 0x61, 0x73,
0x68, 0x22, 0x3a, 0x22, 0x30, 0x78, 0x32, 0x30,
0x38, 0x36, 0x37, 0x39, 0x39, 0x61, 0x65, 0x65,
0x62, 0x65, 0x61, 0x65, 0x31, 0x33, 0x35, 0x63,
0x32, 0x34, 0x36, 0x63, 0x36, 0x35, 0x30, 0x32,
0x31, 0x63, 0x38, 0x32, 0x62, 0x34, 0x65, 0x31,
0x35, 0x61, 0x32, 0x63, 0x34, 0x35, 0x31, 0x33,
0x34, 0x30, 0x39, 0x39, 0x33, 0x61, 0x61, 0x63,
0x66, 0x64, 0x32, 0x37, 0x35, 0x31, 0x38, 0x38,
0x36, 0x35, 0x31, 0x34, 0x66, 0x30, 0x22, 0x2c,
0x22, 0x65, 0x69, 0x70, 0x31, 0x35, 0x35, 0x42,
0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x3a, 0x30, 0x2c,
0x22, 0x65, 0x69, 0x70, 0x31, 0x35, 0x38, 0x42,
0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x3a, 0x30, 0x2c,
0x22, 0x62, 0x79, 0x7a, 0x61, 0x6e, 0x74, 0x69,
0x75, 0x6d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x22,
0x3a, 0x30, 0x2c, 0x22, 0x63, 0x6f, 0x6e, 0x73,
0x74, 0x61, 0x6e, 0x74, 0x69, 0x6e, 0x6f, 0x70,
0x6c, 0x65, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x22,
0x3a, 0x30, 0x2c, 0x22, 0x70, 0x65, 0x74, 0x65,
0x72, 0x73, 0x62, 0x75, 0x72, 0x67, 0x42, 0x6c,
0x6f, 0x63, 0x6b, 0x22, 0x3a, 0x30, 0x7d, 0x2c,
0x22, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x22, 0x3a,
0x22, 0x30, 0x78, 0x30, 0x22, 0x2c, 0x22, 0x74,
0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70,
0x22, 0x3a, 0x22, 0x30, 0x78, 0x30, 0x22, 0x2c,
0x22, 0x65, 0x78, 0x74, 0x72, 0x61, 0x44, 0x61,
0x74, 0x61, 0x22, 0x3a, 0x22, 0x30, 0x78, 0x30,
0x30, 0x22, 0x2c, 0x22, 0x67, 0x61, 0x73, 0x4c,
0x69, 0x6d, 0x69, 0x74, 0x22, 0x3a, 0x22, 0x30,
0x78, 0x35, 0x66, 0x35, 0x65, 0x31, 0x30, 0x30,
0x22, 0x2c, 0x22, 0x64, 0x69, 0x66, 0x66, 0x69,
0x63, 0x75, 0x6c, 0x74, 0x79, 0x22, 0x3a, 0x22,
0x30, 0x78, 0x30, 0x22, 0x2c, 0x22, 0x6d, 0x69,
0x78, 0x48, 0x61, 0x73, 0x68, 0x22, 0x3a, 0x22,
0x30, 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
0x30, 0x30, 0x22, 0x2c, 0x22, 0x63, 0x6f, 0x69,
0x6e, 0x62, 0x61, 0x73, 0x65, 0x22, 0x3a, 0x22,
0x30, 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
0x30, 0x30, 0x22, 0x2c, 0x22, 0x61, 0x6c, 0x6c,
0x6f, 0x63, 0x22, 0x3a, 0x7b, 0x22, 0x37, 0x35,
0x31, 0x61, 0x30, 0x62, 0x39, 0x36, 0x65, 0x31,
0x30, 0x34, 0x32, 0x62, 0x65, 0x65, 0x37, 0x38,
0x39, 0x34, 0x35, 0x32, 0x65, 0x63, 0x62, 0x32,
0x30, 0x32, 0x35, 0x33, 0x66, 0x62, 0x61, 0x34,
0x30, 0x64, 0x62, 0x65, 0x38, 0x35, 0x22, 0x3a,
0x7b, 0x22, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63,
0x65, 0x22, 0x3a, 0x22, 0x30, 0x78, 0x33, 0x33,
0x62, 0x32, 0x65, 0x33, 0x63, 0x39, 0x66, 0x64,
0x30, 0x38, 0x30, 0x34, 0x30, 0x30, 0x30, 0x30,
0x30, 0x30, 0x30, 0x30, 0x30, 0x22, 0x7d, 0x7d,
0x2c, 0x22, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72,
0x22, 0x3a, 0x22, 0x30, 0x78, 0x30, 0x22, 0x2c,
0x22, 0x67, 0x61, 0x73, 0x55, 0x73, 0x65, 0x64,
0x22, 0x3a, 0x22, 0x30, 0x78, 0x30, 0x22, 0x2c,
0x22, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x48,
0x61, 0x73, 0x68, 0x22, 0x3a, 0x22, 0x30, 0x78,
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
0x22, 0x7d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x39, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x13, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x20,
0x44, 0x41, 0x47, 0x20, 0x50, 0x61, 0x79, 0x6d,
0x65, 0x6e, 0x74, 0x73, 0x73, 0x70, 0x64, 0x61,
0x67, 0x76, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x02,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x30,
0x9c, 0xe5, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x01, 0x3c, 0xb7, 0xd3, 0x84,
0x2e, 0x8c, 0xee, 0x6a, 0x0e, 0xbd, 0x09, 0xf1,
0xfe, 0x88, 0x4f, 0x68, 0x61, 0xe1, 0xb2, 0x9c,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30,
0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x15, 0x53, 0x69, 0x6d, 0x70, 0x6c,
0x65, 0x20, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x20,
0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73,
0x73, 0x70, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x76,
0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28,
0x00, 0x00, 0x00, 0x01, 0x3c, 0xb7, 0xd3, 0x84,
0x2e, 0x8c, 0xee, 0x6a, 0x0e, 0xbd, 0x09, 0xf1,
0xfe, 0x88, 0x4f, 0x68, 0x61, 0xe1, 0xb2, 0x9c,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x12, 0x30, 0x9c, 0xe5, 0x40, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x30, 0x39, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x53,
0x69, 0x6d, 0x70, 0x6c, 0x65, 0x20, 0x54, 0x69,
0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x20,
0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x74, 0x69,
0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x5d, 0xbb, 0x75, 0x80,
// Specify the genesis state of the AVM
avmArgs := avm.BuildGenesisArgs{}
{
holders := []interface{}(nil)
for _, addr := range Addresses {
holders = append(holders, avm.Holder{
Amount: json.Uint64(45 * units.MegaAva),
Address: addr,
})
}
avmArgs.GenesisData = map[string]avm.AssetDefinition{
// The AVM starts out with one asset, $AVA
"AVA": avm.AssetDefinition{
Name: "AVA",
Symbol: "AVA",
Denomination: 9,
InitialState: map[string][]interface{}{
"fixedCap": holders,
},
},
}
}
avmReply := avm.BuildGenesisReply{}
avmSS := avm.StaticService{}
err := avmSS.BuildGenesis(nil, &avmArgs, &avmReply)
if err != nil {
panic(err)
}
// Specify the genesis state of Athereum (the built-in instance of the EVM)
evmBalance, success := new(big.Int).SetString("33b2e3c9fd0804000000000", 16)
if success != true {
return nil
}
evmArgs := core.Genesis{
Config: &params.ChainConfig{
ChainID: big.NewInt(43110),
HomesteadBlock: big.NewInt(0),
DAOForkBlock: big.NewInt(0),
DAOForkSupport: true,
EIP150Block: big.NewInt(0),
EIP150Hash: common.HexToHash("0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0"),
EIP155Block: big.NewInt(0),
EIP158Block: big.NewInt(0),
ByzantiumBlock: big.NewInt(0),
ConstantinopleBlock: big.NewInt(0),
PetersburgBlock: big.NewInt(0),
},
Nonce: 0,
Timestamp: 0,
ExtraData: []byte{0},
GasLimit: 100000000,
Difficulty: big.NewInt(0),
Mixhash: common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"),
Coinbase: common.HexToAddress("0x0000000000000000000000000000000000000000"),
Alloc: core.GenesisAlloc{
common.HexToAddress(evm.GenesisTestAddr): core.GenesisAccount{
Balance: evmBalance,
},
},
Number: 0,
GasUsed: 0,
ParentHash: common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"),
}
evmSS := evm.StaticService{}
evmReply, err := evmSS.BuildGenesis(nil, &evmArgs)
if err != nil {
return nil
}
// Specify the genesis state of the simple payments DAG
spdagvmArgs := spdagvm.BuildGenesisArgs{}
for _, addr := range ParsedAddresses {
spdagvmArgs.Outputs = append(spdagvmArgs.Outputs,
spdagvm.APIOutput{
Amount: json.Uint64(20 * units.KiloAva),
Threshold: 1,
Addresses: []ids.ShortID{addr},
},
)
}
spdagvmReply := spdagvm.BuildGenesisReply{}
spdagvmSS := spdagvm.StaticService{}
if err := spdagvmSS.BuildGenesis(nil, &spdagvmArgs, &spdagvmReply); err != nil {
return nil
}
// Specify the genesis state of the simple payments chain
spchainvmArgs := spchainvm.BuildGenesisArgs{}
for _, addr := range ParsedAddresses {
spchainvmArgs.Accounts = append(spchainvmArgs.Accounts,
spchainvm.APIAccount{
Address: addr,
Balance: json.Uint64(20 * units.KiloAva),
},
)
}
spchainvmReply := spchainvm.BuildGenesisReply{}
spchainvmSS := spchainvm.StaticService{}
if err := spchainvmSS.BuildGenesis(nil, &spchainvmArgs, &spchainvmReply); err != nil {
return nil
}
// Specify the initial state of the Platform Chain
platformvmArgs := platformvm.BuildGenesisArgs{
NetworkID: json.Uint32(networkID),
}
for _, addr := range ParsedAddresses {
platformvmArgs.Accounts = append(platformvmArgs.Accounts,
platformvm.APIAccount{
Address: addr,
Balance: json.Uint64(20 * units.KiloAva),
},
)
}
genesisTime := time.Date(
/*year=*/ 2019,
/*month=*/ time.November,
/*day=*/ 1,
/*hour=*/ 0,
/*minute=*/ 0,
/*second=*/ 0,
/*nano-second=*/ 0,
/*location=*/ time.UTC,
)
stakingDuration := 365 * 24 * time.Hour // ~ 1 year
endStakingTime := genesisTime.Add(stakingDuration)
for i, validatorID := range ParsedStakerIDs {
weight := json.Uint64(20 * units.KiloAva)
platformvmArgs.Validators = append(platformvmArgs.Validators,
platformvm.APIDefaultSubnetValidator{
APIValidator: platformvm.APIValidator{
StartTime: json.Uint64(genesisTime.Unix()),
EndTime: json.Uint64(endStakingTime.Unix()),
Weight: &weight,
ID: validatorID,
},
Destination: ParsedAddresses[i%len(ParsedAddresses)],
},
)
}
// Specify the chains that exist upon this network's creation
platformvmArgs.Chains = []platformvm.APIChain{
platformvm.APIChain{
GenesisData: avmReply.Bytes,
VMID: avm.ID,
FxIDs: []ids.ID{
secp256k1fx.ID,
nftfx.ID,
},
Name: "X-Chain",
},
platformvm.APIChain{
GenesisData: evmReply,
VMID: evm.ID,
Name: "C-Chain",
},
platformvm.APIChain{
GenesisData: spdagvmReply.Bytes,
VMID: spdagvm.ID,
Name: "Simple DAG Payments",
},
platformvm.APIChain{
GenesisData: spchainvmReply.Bytes,
VMID: spchainvm.ID,
Name: "Simple Chain Payments",
},
platformvm.APIChain{
GenesisData: formatting.CB58{Bytes: []byte{}}, // There is no genesis data
VMID: timestampvm.ID,
Name: "Simple Timestamp Server",
},
}
platformvmArgs.Time = json.Uint64(genesisTime.Unix())
platformvmReply := platformvm.BuildGenesisReply{}
platformvmSS := platformvm.StaticService{}
if err := platformvmSS.BuildGenesis(nil, &platformvmArgs, &platformvmReply); err != nil {
return nil
}
return platformvmReply.Bytes.Bytes
}
// VMGenesis ...

View File

@ -39,6 +39,7 @@ import (
"github.com/ava-labs/gecko/vms"
"github.com/ava-labs/gecko/vms/avm"
"github.com/ava-labs/gecko/vms/evm"
"github.com/ava-labs/gecko/vms/nftfx"
"github.com/ava-labs/gecko/vms/platformvm"
"github.com/ava-labs/gecko/vms/secp256k1fx"
"github.com/ava-labs/gecko/vms/spchainvm"
@ -333,8 +334,9 @@ func (n *Node) initVMManager() {
n.vmManager.RegisterVMFactory(evm.ID, &evm.Factory{})
n.vmManager.RegisterVMFactory(spdagvm.ID, &spdagvm.Factory{TxFee: n.Config.AvaTxFee})
n.vmManager.RegisterVMFactory(spchainvm.ID, &spchainvm.Factory{})
n.vmManager.RegisterVMFactory(secp256k1fx.ID, &secp256k1fx.Factory{})
n.vmManager.RegisterVMFactory(timestampvm.ID, &timestampvm.Factory{})
n.vmManager.RegisterVMFactory(secp256k1fx.ID, &secp256k1fx.Factory{})
n.vmManager.RegisterVMFactory(nftfx.ID, &nftfx.Factory{})
}
// Create the EventDispatcher used for hooking events

View File

@ -10,6 +10,7 @@ import (
"github.com/ava-labs/gecko/ids"
"github.com/ava-labs/gecko/utils/formatting"
"github.com/ava-labs/gecko/utils/wrappers"
"github.com/ava-labs/gecko/vms/components/codec"
"github.com/ava-labs/gecko/vms/secp256k1fx"
@ -44,17 +45,24 @@ type BuildGenesisReply struct {
// BuildGenesis returns the UTXOs such that at least one address in [args.Addresses] is
// referenced in the UTXO.
func (*StaticService) BuildGenesis(_ *http.Request, args *BuildGenesisArgs, reply *BuildGenesisReply) error {
errs := wrappers.Errs{}
c := codec.NewDefault()
c.RegisterType(&BaseTx{})
c.RegisterType(&CreateAssetTx{})
c.RegisterType(&OperationTx{})
c.RegisterType(&ImportTx{})
c.RegisterType(&ExportTx{})
c.RegisterType(&secp256k1fx.TransferInput{})
c.RegisterType(&secp256k1fx.MintOutput{})
c.RegisterType(&secp256k1fx.TransferOutput{})
c.RegisterType(&secp256k1fx.MintOperation{})
c.RegisterType(&secp256k1fx.Credential{})
errs.Add(
c.RegisterType(&BaseTx{}),
c.RegisterType(&CreateAssetTx{}),
c.RegisterType(&OperationTx{}),
c.RegisterType(&ImportTx{}),
c.RegisterType(&ExportTx{}),
c.RegisterType(&secp256k1fx.TransferInput{}),
c.RegisterType(&secp256k1fx.MintOutput{}),
c.RegisterType(&secp256k1fx.TransferOutput{}),
c.RegisterType(&secp256k1fx.MintOperation{}),
c.RegisterType(&secp256k1fx.Credential{}),
)
if errs.Errored() {
return errs.Err
}
g := Genesis{}
for assetAlias, assetDefinition := range args.GenesisData {

View File

@ -116,24 +116,24 @@ func (vm *VM) Initialize(
vm.Aliaser.Initialize()
vm.pubsub = cjson.NewPubSubServer(ctx)
c := codec.NewDefault()
errs := wrappers.Errs{}
errs.Add(
vm.pubsub.Register("accepted"),
vm.pubsub.Register("rejected"),
vm.pubsub.Register("verified"),
c.RegisterType(&BaseTx{}),
c.RegisterType(&CreateAssetTx{}),
c.RegisterType(&OperationTx{}),
c.RegisterType(&ImportTx{}),
c.RegisterType(&ExportTx{}),
)
if errs.Errored() {
return errs.Err
}
c := codec.NewDefault()
c.RegisterType(&BaseTx{})
c.RegisterType(&CreateAssetTx{})
c.RegisterType(&OperationTx{})
c.RegisterType(&ImportTx{})
c.RegisterType(&ExportTx{})
vm.fxs = make([]*parsedFx, len(fxs))
for i, fxContainer := range fxs {
if fxContainer == nil {

View File

@ -18,6 +18,7 @@ import (
"github.com/ava-labs/gecko/vms/components/ava"
"github.com/ava-labs/gecko/vms/components/codec"
"github.com/ava-labs/gecko/vms/components/verify"
"github.com/ava-labs/gecko/vms/nftfx"
"github.com/ava-labs/gecko/vms/secp256k1fx"
)
@ -696,3 +697,159 @@ func TestIssueDependentTx(t *testing.T) {
t.Fatalf("Should have returned %d tx(s)", 2)
}
}
// Test issuing a transaction that creates an NFT family
func TestIssueNFT(t *testing.T) {
genesisBytes := BuildGenesisTest(t)
issuer := make(chan common.Message, 1)
ctx.Lock.Lock()
vm := &VM{}
err := vm.Initialize(
ctx,
memdb.New(),
genesisBytes,
issuer,
[]*common.Fx{
&common.Fx{
ID: ids.Empty.Prefix(0),
Fx: &secp256k1fx.Fx{},
},
&common.Fx{
ID: ids.Empty.Prefix(1),
Fx: &nftfx.Fx{},
},
},
)
if err != nil {
t.Fatal(err)
}
vm.batchTimeout = 0
createAssetTx := &Tx{UnsignedTx: &CreateAssetTx{
BaseTx: BaseTx{
NetID: networkID,
BCID: chainID,
},
Name: "Team Rocket",
Symbol: "TR",
Denomination: 0,
States: []*InitialState{&InitialState{
FxID: 1,
Outs: []verify.Verifiable{
&nftfx.MintOutput{
GroupID: 1,
OutputOwners: secp256k1fx.OutputOwners{
Threshold: 1,
Addrs: []ids.ShortID{keys[0].PublicKey().Address()},
},
},
&nftfx.MintOutput{
GroupID: 2,
OutputOwners: secp256k1fx.OutputOwners{
Threshold: 1,
Addrs: []ids.ShortID{keys[0].PublicKey().Address()},
},
},
},
}},
}}
b, err := vm.codec.Marshal(createAssetTx)
if err != nil {
t.Fatal(err)
}
createAssetTx.Initialize(b)
if _, err = vm.IssueTx(createAssetTx.Bytes(), nil); err != nil {
t.Fatal(err)
}
mintNFTTx := &Tx{UnsignedTx: &OperationTx{
BaseTx: BaseTx{
NetID: networkID,
BCID: chainID,
},
Ops: []*Operation{&Operation{
Asset: ava.Asset{ID: createAssetTx.ID()},
UTXOIDs: []*ava.UTXOID{&ava.UTXOID{
TxID: createAssetTx.ID(),
OutputIndex: 0,
}},
Op: &nftfx.MintOperation{
MintInput: secp256k1fx.Input{
SigIndices: []uint32{0},
},
GroupID: 1,
Payload: []byte{'h', 'e', 'l', 'l', 'o'},
Outputs: []*secp256k1fx.OutputOwners{
&secp256k1fx.OutputOwners{},
},
},
}},
}}
unsignedBytes, err := vm.codec.Marshal(&mintNFTTx.UnsignedTx)
if err != nil {
t.Fatal(err)
}
key := keys[0]
sig, err := key.Sign(unsignedBytes)
if err != nil {
t.Fatal(err)
}
fixedSig := [crypto.SECP256K1RSigLen]byte{}
copy(fixedSig[:], sig)
mintNFTTx.Creds = append(mintNFTTx.Creds, &nftfx.Credential{Credential: secp256k1fx.Credential{
Sigs: [][crypto.SECP256K1RSigLen]byte{
fixedSig,
}},
})
b, err = vm.codec.Marshal(mintNFTTx)
if err != nil {
t.Fatal(err)
}
mintNFTTx.Initialize(b)
if _, err = vm.IssueTx(mintNFTTx.Bytes(), nil); err != nil {
t.Fatal(err)
}
transferNFTTx := &Tx{UnsignedTx: &OperationTx{
BaseTx: BaseTx{
NetID: networkID,
BCID: chainID,
},
Ops: []*Operation{&Operation{
Asset: ava.Asset{ID: createAssetTx.ID()},
UTXOIDs: []*ava.UTXOID{&ava.UTXOID{
TxID: mintNFTTx.ID(),
OutputIndex: 0,
}},
Op: &nftfx.TransferOperation{
Input: secp256k1fx.Input{},
Output: nftfx.TransferOutput{
GroupID: 1,
Payload: []byte{'h', 'e', 'l', 'l', 'o'},
OutputOwners: secp256k1fx.OutputOwners{},
},
},
}},
}}
transferNFTTx.Creds = append(transferNFTTx.Creds, &nftfx.Credential{})
b, err = vm.codec.Marshal(transferNFTTx)
if err != nil {
t.Fatal(err)
}
transferNFTTx.Initialize(b)
if _, err = vm.IssueTx(transferNFTTx.Bytes(), nil); err != nil {
t.Fatal(err)
}
}

10
vms/nftfx/credential.go Normal file
View File

@ -0,0 +1,10 @@
package nftfx
import (
"github.com/ava-labs/gecko/vms/secp256k1fx"
)
// Credential ...
type Credential struct {
secp256k1fx.Credential `serialize:"true"`
}

16
vms/nftfx/factory.go Normal file
View File

@ -0,0 +1,16 @@
package nftfx
import (
"github.com/ava-labs/gecko/ids"
)
// ID that this Fx uses when labeled
var (
ID = ids.NewID([32]byte{'n', 'f', 't', 'f', 'x'})
)
// Factory ...
type Factory struct{}
// New ...
func (f *Factory) New() interface{} { return &Fx{} }

12
vms/nftfx/factory_test.go Normal file
View File

@ -0,0 +1,12 @@
package nftfx
import (
"testing"
)
func TestFactory(t *testing.T) {
factory := Factory{}
if fx := factory.New(); fx == nil {
t.Fatalf("Factory.New returned nil")
}
}

118
vms/nftfx/fx.go Normal file
View File

@ -0,0 +1,118 @@
package nftfx
import (
"bytes"
"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")
errWrongUniqueID = errors.New("wrong unique ID provided")
errWrongBytes = errors.New("wrong bytes 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(&TransferOutput{}),
c.RegisterType(&MintOperation{}),
c.RegisterType(&TransferOperation{}),
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 *TransferOperation:
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.GroupID != op.GroupID:
return errWrongUniqueID
default:
return fx.Fx.VerifyCredentials(tx, &op.MintInput, &cred.Credential, &out.OutputOwners)
}
}
// VerifyTransferOperation ...
func (fx *Fx) VerifyTransferOperation(tx secp256k1fx.Tx, op *TransferOperation, cred *Credential, utxoIntf interface{}) error {
out, ok := utxoIntf.(*TransferOutput)
if !ok {
return errWrongUTXOType
}
if err := verify.All(op, cred, out); err != nil {
return err
}
switch {
case out.GroupID != op.Output.GroupID:
return errWrongUniqueID
case !bytes.Equal(out.Payload, op.Output.Payload):
return errWrongBytes
default:
return fx.VerifyCredentials(tx, &op.Input, &cred.Credential, &out.OutputOwners)
}
}
// VerifyTransfer ...
func (fx *Fx) VerifyTransfer(_, _, _, _ interface{}) error { return errCantTransfer }

618
vms/nftfx/fx_test.go Normal file
View File

@ -0,0 +1,618 @@
package nftfx
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},
},
}
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},
},
GroupID: 1,
}
utxos := []interface{}{utxo}
if err := fx.VerifyOperation(tx, op, cred, utxos); err == nil {
t.Fatalf("VerifyOperation should have errored due to an invalid Group ID")
}
}
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 := &TransferOutput{
GroupID: 1,
Payload: []byte{2},
OutputOwners: secp256k1fx.OutputOwners{
Threshold: 1,
Addrs: []ids.ShortID{
ids.NewShortID(addrBytes),
},
},
}
op := &TransferOperation{
Input: secp256k1fx.Input{
SigIndices: []uint32{0},
},
Output: TransferOutput{
GroupID: 1,
Payload: []byte{2},
OutputOwners: secp256k1fx.OutputOwners{
Threshold: 1,
Addrs: []ids.ShortID{
ids.ShortEmpty,
},
},
},
}
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 := &TransferOperation{
Input: secp256k1fx.Input{
SigIndices: []uint32{0},
},
Output: TransferOutput{
GroupID: 1,
Payload: []byte{2},
OutputOwners: secp256k1fx.OutputOwners{
Threshold: 1,
Addrs: []ids.ShortID{
ids.ShortEmpty,
},
},
},
}
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 := &TransferOutput{
GroupID: 1,
Payload: []byte{2},
OutputOwners: secp256k1fx.OutputOwners{
Threshold: 1,
},
}
op := &TransferOperation{
Input: secp256k1fx.Input{
SigIndices: []uint32{0},
},
Output: TransferOutput{
GroupID: 1,
Payload: []byte{2},
OutputOwners: secp256k1fx.OutputOwners{
Threshold: 1,
Addrs: []ids.ShortID{
ids.ShortEmpty,
},
},
},
}
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 TestFxVerifyTransferOperationWrongGroupID(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 := &TransferOutput{
GroupID: 1,
Payload: []byte{2},
OutputOwners: secp256k1fx.OutputOwners{
Threshold: 1,
Addrs: []ids.ShortID{
ids.NewShortID(addrBytes),
},
},
}
op := &TransferOperation{
Input: secp256k1fx.Input{
SigIndices: []uint32{0},
},
Output: TransferOutput{
GroupID: 2,
Payload: []byte{2},
OutputOwners: secp256k1fx.OutputOwners{
Threshold: 1,
Addrs: []ids.ShortID{
ids.ShortEmpty,
},
},
},
}
utxos := []interface{}{utxo}
if err := fx.VerifyOperation(tx, op, cred, utxos); err == nil {
t.Fatalf("VerifyOperation should have errored due to a wrong unique id")
}
}
func TestFxVerifyTransferOperationWrongBytes(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 := &TransferOutput{
GroupID: 1,
Payload: []byte{2},
OutputOwners: secp256k1fx.OutputOwners{
Threshold: 1,
Addrs: []ids.ShortID{
ids.NewShortID(addrBytes),
},
},
}
op := &TransferOperation{
Input: secp256k1fx.Input{
SigIndices: []uint32{0},
},
Output: TransferOutput{
GroupID: 1,
Payload: []byte{3},
OutputOwners: secp256k1fx.OutputOwners{
Threshold: 1,
Addrs: []ids.ShortID{
ids.ShortEmpty,
},
},
},
}
utxos := []interface{}{utxo}
if err := fx.VerifyOperation(tx, op, cred, utxos); err == nil {
t.Fatalf("VerifyOperation should have errored due to the wrong hash being produced")
}
}
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 := &TransferOutput{
GroupID: 1,
Payload: []byte{2},
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")
}
}

View File

@ -0,0 +1,50 @@
package nftfx
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"`
GroupID uint32 `serialize:"true"`
Payload []byte `serialize:"true"`
Outputs []*secp256k1fx.OutputOwners `serialize:"true"`
}
// Outs ...
func (op *MintOperation) Outs() []verify.Verifiable {
outs := []verify.Verifiable{}
for _, out := range op.Outputs {
outs = append(outs, &TransferOutput{
GroupID: op.GroupID,
Payload: op.Payload,
OutputOwners: *out,
})
}
return outs
}
// Verify ...
func (op *MintOperation) Verify() error {
switch {
case op == nil:
return errNilMintOperation
case len(op.Payload) > MaxPayloadSize:
return errPayloadTooLarge
}
for _, out := range op.Outputs {
if err := out.Verify(); err != nil {
return err
}
}
return op.MintInput.Verify()
}

View File

@ -0,0 +1,43 @@
package nftfx
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 TestMintOperationVerifyTooLargePayload(t *testing.T) {
op := MintOperation{
Payload: make([]byte, MaxPayloadSize+1),
}
if err := op.Verify(); err == nil {
t.Fatalf("operation should have failed verification")
}
}
func TestMintOperationVerifyInvalidOutput(t *testing.T) {
op := MintOperation{
Outputs: []*secp256k1fx.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{
Outputs: []*secp256k1fx.OutputOwners{&secp256k1fx.OutputOwners{}},
}
if outs := op.Outs(); len(outs) != 1 {
t.Fatalf("Wrong number of outputs returned")
}
}

11
vms/nftfx/mint_output.go Normal file
View File

@ -0,0 +1,11 @@
package nftfx
import (
"github.com/ava-labs/gecko/vms/secp256k1fx"
)
// MintOutput ...
type MintOutput struct {
GroupID uint32 `serialize:"true"`
secp256k1fx.OutputOwners `serialize:"true"`
}

View File

@ -0,0 +1,33 @@
package nftfx
import (
"errors"
"github.com/ava-labs/gecko/vms/components/verify"
"github.com/ava-labs/gecko/vms/secp256k1fx"
)
var (
errNilTransferOperation = errors.New("nil transfer operation")
)
// TransferOperation ...
type TransferOperation struct {
Input secp256k1fx.Input `serialize:"true"`
Output TransferOutput `serialize:"true"`
}
// Outs ...
func (op *TransferOperation) Outs() []verify.Verifiable {
return []verify.Verifiable{&op.Output}
}
// Verify ...
func (op *TransferOperation) Verify() error {
switch {
case op == nil:
return errNilTransferOperation
default:
return verify.All(&op.Input, &op.Output)
}
}

View File

@ -0,0 +1,32 @@
package nftfx
import (
"testing"
"github.com/ava-labs/gecko/vms/secp256k1fx"
)
func TestTransferOperationVerifyNil(t *testing.T) {
op := (*TransferOperation)(nil)
if err := op.Verify(); err == nil {
t.Fatalf("nil operation should have failed verification")
}
}
func TestTransferOperationInvalid(t *testing.T) {
op := TransferOperation{Input: secp256k1fx.Input{
SigIndices: []uint32{1, 0},
}}
if err := op.Verify(); err == nil {
t.Fatalf("operation should have failed verification")
}
}
func TestTransferOperationOuts(t *testing.T) {
op := TransferOperation{
Output: TransferOutput{},
}
if outs := op.Outs(); len(outs) != 1 {
t.Fatalf("Wrong number of outputs returned")
}
}

View File

@ -0,0 +1,36 @@
package nftfx
import (
"errors"
"github.com/ava-labs/gecko/vms/secp256k1fx"
)
const (
// MaxPayloadSize is the maximum size that can be placed into a payload
MaxPayloadSize = 1 << 10
)
var (
errNilTransferOutput = errors.New("nil transfer output")
errPayloadTooLarge = errors.New("payload too large")
)
// TransferOutput ...
type TransferOutput struct {
GroupID uint32 `serialize:"true"`
Payload []byte `serialize:"true"`
secp256k1fx.OutputOwners `serialize:"true"`
}
// Verify ...
func (out *TransferOutput) Verify() error {
switch {
case out == nil:
return errNilTransferOutput
case len(out.Payload) > MaxPayloadSize:
return errPayloadTooLarge
default:
return out.OutputOwners.Verify()
}
}

View File

@ -0,0 +1,38 @@
package nftfx
import (
"testing"
"github.com/ava-labs/gecko/ids"
"github.com/ava-labs/gecko/vms/secp256k1fx"
)
func TestTransferOutputVerifyNil(t *testing.T) {
to := (*TransferOutput)(nil)
if err := to.Verify(); err == nil {
t.Fatalf("TransferOutput.Verify should have errored on nil")
}
}
func TestTransferOutputLargePayload(t *testing.T) {
to := TransferOutput{
Payload: make([]byte, MaxPayloadSize+1),
}
if err := to.Verify(); err == nil {
t.Fatalf("TransferOutput.Verify should have errored on too large of a payload")
}
}
func TestTransferOutputInvalidSecp256k1Output(t *testing.T) {
to := TransferOutput{
OutputOwners: secp256k1fx.OutputOwners{
Addrs: []ids.ShortID{
ids.ShortEmpty,
ids.ShortEmpty,
},
},
}
if err := to.Verify(); err == nil {
t.Fatalf("TransferOutput.Verify should have errored on too large of a payload")
}
}

View File

@ -7,3 +7,9 @@ package secp256k1fx
type Tx interface {
UnsignedBytes() []byte
}
// TestTx is a minimal implementation of a Tx
type TestTx struct{ Bytes []byte }
// UnsignedBytes returns Bytes
func (tx *TestTx) UnsignedBytes() []byte { return tx.Bytes }

View File

@ -15,3 +15,19 @@ type VM interface {
Clock() *timer.Clock
Logger() logging.Logger
}
// TestVM is a minimal implementation of a VM
type TestVM struct {
CLK *timer.Clock
Code codec.Codec
Log logging.Logger
}
// Clock returns CLK
func (vm *TestVM) Clock() *timer.Clock { return vm.CLK }
// Codec returns Code
func (vm *TestVM) Codec() codec.Codec { return vm.Code }
// Logger returns Log
func (vm *TestVM) Logger() logging.Logger { return vm.Log }