gecko/genesis/genesis.go

273 lines
7.6 KiB
Go

// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package genesis
import (
"errors"
"fmt"
"time"
"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/utils/wrappers"
"github.com/ava-labs/gecko/vms/avm"
"github.com/ava-labs/gecko/utils/codec"
"github.com/ava-labs/gecko/vms/nftfx"
"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/spchainvm"
"github.com/ava-labs/gecko/vms/spdagvm"
"github.com/ava-labs/gecko/vms/timestampvm"
)
// ID of the EVM VM
var (
EVMID = ids.NewID([32]byte{'e', 'v', 'm'})
)
// Genesis returns the genesis data of the Platform Chain.
// Since an AVA network has exactly one Platform Chain, and the Platform Chain
// defines the genesis state of the network (who is staking, which chains exist,
// etc.), defining the genesis state of the Platform Chain is the same as
// defining the genesis state of the network.
// The ID of the new network is [networkID].
// FromConfig ...
func FromConfig(networkID uint32, config *Config) ([]byte, error) {
if err := config.init(); err != nil {
return nil, err
}
// Specify the genesis state of the AVM
avmArgs := avm.BuildGenesisArgs{}
{
ava := avm.AssetDefinition{
Name: "AVA",
Symbol: "AVA",
Denomination: 9,
InitialState: map[string][]interface{}{},
}
if len(config.MintAddresses) > 0 {
ava.InitialState["variableCap"] = []interface{}{avm.Owners{
Threshold: 1,
Minters: config.MintAddresses,
}}
}
for _, addr := range config.FundedAddresses {
ava.InitialState["fixedCap"] = append(ava.InitialState["fixedCap"], 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": ava,
}
}
avmReply := avm.BuildGenesisReply{}
avmSS := avm.StaticService{}
err := avmSS.BuildGenesis(nil, &avmArgs, &avmReply)
if err != nil {
return nil, err
}
// Specify the genesis state of the simple payments DAG
spdagvmArgs := spdagvm.BuildGenesisArgs{}
for _, addr := range config.ParsedFundedAddresses {
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, fmt.Errorf("problem creating simple payments DAG: %w", err)
}
// Specify the genesis state of the simple payments chain
spchainvmArgs := spchainvm.BuildGenesisArgs{}
for _, addr := range config.ParsedFundedAddresses {
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, fmt.Errorf("problem creating simple payments chain: %w", err)
}
// Specify the initial state of the Platform Chain
platformvmArgs := platformvm.BuildGenesisArgs{
NetworkID: json.Uint32(networkID),
}
for _, addr := range config.ParsedFundedAddresses {
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 config.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: config.ParsedFundedAddresses[i%len(config.ParsedFundedAddresses)],
},
)
}
// Specify the chains that exist upon this network's creation
platformvmArgs.Chains = []platformvm.APIChain{
platformvm.APIChain{
GenesisData: avmReply.Bytes,
SubnetID: platformvm.DefaultSubnetID,
VMID: avm.ID,
FxIDs: []ids.ID{
secp256k1fx.ID,
nftfx.ID,
propertyfx.ID,
},
Name: "X-Chain",
},
platformvm.APIChain{
GenesisData: formatting.CB58{Bytes: config.EVMBytes},
SubnetID: platformvm.DefaultSubnetID,
VMID: EVMID,
Name: "C-Chain",
},
platformvm.APIChain{
GenesisData: spdagvmReply.Bytes,
SubnetID: platformvm.DefaultSubnetID,
VMID: spdagvm.ID,
Name: "Simple DAG Payments",
},
platformvm.APIChain{
GenesisData: spchainvmReply.Bytes,
SubnetID: platformvm.DefaultSubnetID,
VMID: spchainvm.ID,
Name: "Simple Chain Payments",
},
platformvm.APIChain{
GenesisData: formatting.CB58{Bytes: []byte{}}, // There is no genesis data
SubnetID: platformvm.DefaultSubnetID,
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, fmt.Errorf("problem while building platform chain's genesis state: %w", err)
}
return platformvmReply.Bytes.Bytes, nil
}
// Genesis ...
func Genesis(networkID uint32) ([]byte, error) { return FromConfig(networkID, GetConfig(networkID)) }
// VMGenesis ...
func VMGenesis(networkID uint32, vmID ids.ID) (*platformvm.CreateChainTx, error) {
genesisBytes, err := Genesis(networkID)
if err != nil {
return nil, err
}
genesis := platformvm.Genesis{}
platformvm.Codec.Unmarshal(genesisBytes, &genesis)
if err := genesis.Initialize(); err != nil {
return nil, err
}
for _, chain := range genesis.Chains {
if chain.VMID.Equals(vmID) {
return chain, nil
}
}
return nil, fmt.Errorf("couldn't find subnet with VM ID %s", vmID)
}
// AVAAssetID ...
func AVAAssetID(networkID uint32) (ids.ID, error) {
createAVM, err := VMGenesis(networkID, avm.ID)
if err != nil {
return ids.ID{}, err
}
c := codec.NewDefault()
errs := wrappers.Errs{}
errs.Add(
c.RegisterType(&avm.BaseTx{}),
c.RegisterType(&avm.CreateAssetTx{}),
c.RegisterType(&avm.OperationTx{}),
c.RegisterType(&avm.ImportTx{}),
c.RegisterType(&avm.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 ids.ID{}, errs.Err
}
genesis := avm.Genesis{}
if err := c.Unmarshal(createAVM.GenesisData, &genesis); err != nil {
return ids.ID{}, err
}
if len(genesis.Txs) == 0 {
return ids.ID{}, errors.New("genesis creates no transactions")
}
genesisTx := genesis.Txs[0]
tx := avm.Tx{UnsignedTx: &genesisTx.CreateAssetTx}
txBytes, err := c.Marshal(&tx)
if err != nil {
return ids.ID{}, err
}
tx.Initialize(txBytes)
return tx.ID(), nil
}