mirror of https://github.com/poanetwork/gecko.git
merged
This commit is contained in:
commit
4d34dc042d
|
@ -93,6 +93,7 @@ type manager struct {
|
|||
// That is, [chainID].String() is an alias for the chain, too
|
||||
ids.Aliaser
|
||||
|
||||
stakingEnabled bool // True iff the network has staking enabled
|
||||
log logging.Logger
|
||||
logFactory logging.Factory
|
||||
vmManager vms.Manager // Manage mappings from vm ID --> vm
|
||||
|
@ -122,6 +123,7 @@ type manager struct {
|
|||
// <validators> validate this chain
|
||||
// TODO: Make this function take less arguments
|
||||
func New(
|
||||
stakingEnabled bool,
|
||||
log logging.Logger,
|
||||
logFactory logging.Factory,
|
||||
vmManager vms.Manager,
|
||||
|
@ -146,6 +148,7 @@ func New(
|
|||
router.Initialize(log, &timeoutManager)
|
||||
|
||||
m := &manager{
|
||||
stakingEnabled: stakingEnabled,
|
||||
log: log,
|
||||
logFactory: logFactory,
|
||||
vmManager: vmManager,
|
||||
|
@ -261,7 +264,13 @@ func (m *manager) ForceCreateChain(chain ChainParameters) {
|
|||
}
|
||||
|
||||
// The validators of this blockchain
|
||||
validators, ok := m.validators.GetValidatorSet(ids.Empty) // TODO: Change argument to chain.SubnetID
|
||||
var validators validators.Set // Validators validating this blockchain
|
||||
var ok bool
|
||||
if m.stakingEnabled {
|
||||
validators, ok = m.validators.GetValidatorSet(chain.SubnetID)
|
||||
} else { // Staking is disabled. Every peer validates every subnet.
|
||||
validators, ok = m.validators.GetValidatorSet(ids.Empty) // ids.Empty is the default subnet ID. TODO: Move to const package so we can use it here.
|
||||
}
|
||||
if !ok {
|
||||
m.log.Error("couldn't get validator set of subnet with ID %s. The subnet may not exist", chain.SubnetID)
|
||||
return
|
||||
|
@ -358,7 +367,7 @@ func (m *manager) createAvalancheChain(
|
|||
msgChan := make(chan common.Message, defaultChannelSize)
|
||||
|
||||
if err := vm.Initialize(ctx, vmDB, genesisData, msgChan, fxs); err != nil {
|
||||
return err
|
||||
return fmt.Errorf("error during vm's Initialize: %w", err)
|
||||
}
|
||||
|
||||
// Handles serialization/deserialization of vertices and also the
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
package chains
|
||||
|
||||
import (
|
||||
"github.com/ava-labs/gecko/ids"
|
||||
"github.com/ava-labs/gecko/snow/networking/router"
|
||||
)
|
||||
|
||||
// MockManager implements Manager but does nothing. Always returns nil error.
|
||||
// To be used only in tests (namely in package platformvm)
|
||||
type MockManager struct{}
|
||||
|
||||
// Router ...
|
||||
func (mm MockManager) Router() router.Router { return nil }
|
||||
|
||||
// CreateChain ...
|
||||
func (mm MockManager) CreateChain(ChainParameters) {}
|
||||
|
||||
// ForceCreateChain ...
|
||||
func (mm MockManager) ForceCreateChain(ChainParameters) {}
|
||||
|
||||
// AddRegistrant ...
|
||||
func (mm MockManager) AddRegistrant(Registrant) {}
|
||||
|
||||
// Lookup ...
|
||||
func (mm MockManager) Lookup(string) (ids.ID, error) { return ids.ID{}, nil }
|
||||
|
||||
// LookupVM ...
|
||||
func (mm MockManager) LookupVM(string) (ids.ID, error) { return ids.ID{}, nil }
|
||||
|
||||
// Aliases ...
|
||||
func (mm MockManager) Aliases(ids.ID) []string { return nil }
|
||||
|
||||
// Alias ...
|
||||
func (mm MockManager) Alias(ids.ID, string) error { return nil }
|
||||
|
||||
// Shutdown ...
|
||||
func (mm MockManager) Shutdown() {}
|
|
@ -3,16 +3,25 @@
|
|||
|
||||
package genesis
|
||||
|
||||
// TODO: Move this to a separate repo and leave only a byte array
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"math/big"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/ava-labs/coreth/core"
|
||||
|
||||
"github.com/ava-labs/go-ethereum/common"
|
||||
"github.com/ava-labs/go-ethereum/params"
|
||||
|
||||
"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"
|
||||
|
@ -149,9 +158,10 @@ 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"},
|
||||
}
|
||||
|
||||
genesisBytes := Genesis(networkID)
|
||||
genesisBytes, _ := Genesis(networkID)
|
||||
genesis := &platformvm.Genesis{} // TODO let's not re-create genesis to do aliasing
|
||||
platformvm.Codec.Unmarshal(genesisBytes, genesis) // TODO check for error
|
||||
genesis.Initialize()
|
||||
|
@ -182,328 +192,205 @@ func Aliases(networkID uint32) (generalAliases map[string][]string, chainAliases
|
|||
// Since the Platform Chain causes the creation of all other
|
||||
// chains, this function returns the genesis data of the entire network.
|
||||
// The ID of the new network is [networkID].
|
||||
func Genesis(networkID uint32) []byte {
|
||||
if networkID != LocalID {
|
||||
panic("unknown network ID provided")
|
||||
func Genesis(networkID uint32) ([]byte, error) {
|
||||
// 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)
|
||||
}
|
||||
|
||||
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, 0x03,
|
||||
0x41, 0x56, 0x4d, 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, 0x06, 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, 0x08, 0x41, 0x74,
|
||||
0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 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 Athereum (the built-in instance of the EVM)
|
||||
evmBalance, success := new(big.Int).SetString("33b2e3c9fd0804000000000", 16)
|
||||
if success != true {
|
||||
return nil, errors.New("problem creating evm genesis state")
|
||||
}
|
||||
evmArgs := core.Genesis{
|
||||
Config: ¶ms.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, err
|
||||
}
|
||||
|
||||
// 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, fmt.Errorf("problem creating simple payments DAG: %w", err)
|
||||
}
|
||||
|
||||
// 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, 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 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,
|
||||
SubnetID: platformvm.DefaultSubnetID,
|
||||
VMID: avm.ID,
|
||||
FxIDs: []ids.ID{
|
||||
secp256k1fx.ID,
|
||||
},
|
||||
Name: "X-Chain",
|
||||
},
|
||||
platformvm.APIChain{
|
||||
GenesisData: evmReply,
|
||||
SubnetID: platformvm.DefaultSubnetID,
|
||||
VMID: evm.ID,
|
||||
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
|
||||
}
|
||||
|
||||
// VMGenesis ...
|
||||
func VMGenesis(networkID uint32, vmID ids.ID) *platformvm.CreateChainTx {
|
||||
genesisBytes := Genesis(networkID)
|
||||
genesisBytes, _ := Genesis(networkID)
|
||||
genesis := platformvm.Genesis{}
|
||||
platformvm.Codec.Unmarshal(genesisBytes, &genesis)
|
||||
if err := genesis.Initialize(); err != nil {
|
||||
|
|
|
@ -106,7 +106,7 @@ func TestAliases(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestGenesis(t *testing.T) {
|
||||
genesisBytes := Genesis(LocalID)
|
||||
genesisBytes, _ := Genesis(LocalID)
|
||||
genesis := platformvm.Genesis{}
|
||||
if err := platformvm.Codec.Unmarshal(genesisBytes, &genesis); err != nil {
|
||||
t.Fatal(err)
|
||||
|
|
|
@ -120,10 +120,6 @@ func init() {
|
|||
networkID, err := genesis.NetworkID(*networkName)
|
||||
errs.Add(err)
|
||||
|
||||
if networkID != genesis.LocalID {
|
||||
errs.Add(fmt.Errorf("the only supported networkID is: %s", genesis.LocalName))
|
||||
}
|
||||
|
||||
Config.NetworkID = networkID
|
||||
|
||||
// DB:
|
||||
|
|
18
node/node.go
18
node/node.go
|
@ -354,8 +354,13 @@ func (n *Node) initChains() {
|
|||
n.Log.Info("initializing chains")
|
||||
|
||||
vdrs := n.vdrs
|
||||
|
||||
// If staking is disabled, ignore updates to Subnets' validator sets
|
||||
// Instead of updating node's validator manager, platform chain makes changes
|
||||
// to its own local validator manager (which isn't used for sampling)
|
||||
if !n.Config.EnableStaking {
|
||||
defaultSubnetValidators := validators.NewSet()
|
||||
defaultSubnetValidators.Add(validators.NewValidator(n.ID, 1))
|
||||
vdrs = validators.NewManager()
|
||||
vdrs.PutValidatorSet(platformvm.DefaultSubnetID, defaultSubnetValidators)
|
||||
}
|
||||
|
@ -363,10 +368,11 @@ func (n *Node) initChains() {
|
|||
n.vmManager.RegisterVMFactory(
|
||||
/*vmID=*/ platformvm.ID,
|
||||
/*vmFactory=*/ &platformvm.Factory{
|
||||
ChainManager: n.chainManager,
|
||||
Validators: vdrs,
|
||||
AVA: genesis.AVAAssetID(n.Config.NetworkID),
|
||||
AVM: genesis.VMGenesis(n.Config.NetworkID, avm.ID).ID(),
|
||||
ChainManager: n.chainManager,
|
||||
Validators: vdrs,
|
||||
StakingEnabled: n.Config.EnableStaking,
|
||||
AVA: genesis.AVAAssetID(n.Config.NetworkID),
|
||||
AVM: genesis.VMGenesis(n.Config.NetworkID, avm.ID).ID(),
|
||||
},
|
||||
)
|
||||
|
||||
|
@ -375,11 +381,12 @@ func (n *Node) initChains() {
|
|||
beacons.Add(validators.NewValidator(peer.ID, 1))
|
||||
}
|
||||
|
||||
genesisBytes := genesis.Genesis(n.Config.NetworkID)
|
||||
genesisBytes, _ := genesis.Genesis(n.Config.NetworkID)
|
||||
|
||||
// Create the Platform Chain
|
||||
n.chainManager.ForceCreateChain(chains.ChainParameters{
|
||||
ID: ids.Empty,
|
||||
SubnetID: platformvm.DefaultSubnetID,
|
||||
GenesisData: genesisBytes, // Specifies other chains to create
|
||||
VMAlias: platformvm.ID.String(),
|
||||
CustomBeacons: beacons,
|
||||
|
@ -409,6 +416,7 @@ func (n *Node) initAPIServer() {
|
|||
// Assumes n.DB, n.vdrs all initialized (non-nil)
|
||||
func (n *Node) initChainManager() {
|
||||
n.chainManager = chains.New(
|
||||
n.Config.EnableStaking,
|
||||
n.Log,
|
||||
n.LogFactory,
|
||||
n.vmManager,
|
||||
|
|
|
@ -7,6 +7,8 @@ import (
|
|||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/ava-labs/gecko/ids"
|
||||
|
||||
"github.com/ava-labs/gecko/database"
|
||||
"github.com/ava-labs/gecko/database/versiondb"
|
||||
)
|
||||
|
@ -86,7 +88,7 @@ func (tx *advanceTimeTx) SemanticVerify(db database.Database) (*versiondb.Databa
|
|||
return nil, nil, nil, nil, err
|
||||
}
|
||||
|
||||
current, pending, err := tx.vm.calculateValidators(db, tx.Timestamp(), DefaultSubnetID)
|
||||
current, pending, _, _, err := tx.vm.calculateValidators(db, tx.Timestamp(), DefaultSubnetID)
|
||||
if err != nil {
|
||||
return nil, nil, nil, nil, err
|
||||
}
|
||||
|
@ -98,29 +100,35 @@ func (tx *advanceTimeTx) SemanticVerify(db database.Database) (*versiondb.Databa
|
|||
return nil, nil, nil, nil, err
|
||||
}
|
||||
|
||||
// For each subnet, calculate what current and pending validator sets should be
|
||||
// For each Subnet, calculate what current and pending validator sets should be
|
||||
// given new timestamp
|
||||
|
||||
// Key: Subnet ID
|
||||
// Value: IDs of validators that will have started validating this Subnet when
|
||||
// timestamp is advanced to tx.Timestamp()
|
||||
startedValidating := make(map[ids.ID]ids.ShortSet, 0)
|
||||
subnets, err := tx.vm.getSubnets(db)
|
||||
if err != nil {
|
||||
return nil, nil, nil, nil, err
|
||||
}
|
||||
for _, subnet := range subnets {
|
||||
current, pending, err := tx.vm.calculateValidators(db, tx.Timestamp(), subnet.id)
|
||||
current, pending, started, _, err := tx.vm.calculateValidators(db, tx.Timestamp(), subnet.id)
|
||||
if err != nil {
|
||||
return nil, nil, nil, nil, err
|
||||
}
|
||||
|
||||
if err := tx.vm.putCurrentValidators(onCommitDB, current, subnet.id); err != nil {
|
||||
return nil, nil, nil, nil, err
|
||||
}
|
||||
if err := tx.vm.putPendingValidators(onCommitDB, pending, subnet.id); err != nil {
|
||||
return nil, nil, nil, nil, err
|
||||
}
|
||||
startedValidating[subnet.ID()] = started
|
||||
}
|
||||
|
||||
// If this block is committed, update the validator sets
|
||||
// onAbortDB or onCommitDB should commit (flush to vm.DB) before this is called
|
||||
updateValidators := func() {
|
||||
onCommitFunc := func() {
|
||||
// For each Subnet, update the node's validator manager to reflect current Subnet membership
|
||||
subnets, err := tx.vm.getSubnets(tx.vm.DB)
|
||||
if err != nil {
|
||||
tx.vm.Ctx.Log.Error("failed to get subnets: %s", err)
|
||||
|
@ -128,18 +136,35 @@ func (tx *advanceTimeTx) SemanticVerify(db database.Database) (*versiondb.Databa
|
|||
}
|
||||
for _, subnet := range subnets {
|
||||
if err := tx.vm.updateValidators(subnet.id); err != nil {
|
||||
tx.vm.Ctx.Log.Debug("failed to update validators on the default subnet: %s", err)
|
||||
tx.vm.Ctx.Log.Debug("failed to update Subnet %s: %s", subnet.id, err)
|
||||
}
|
||||
}
|
||||
if err := tx.vm.updateValidators(DefaultSubnetID); err != nil {
|
||||
tx.vm.Ctx.Log.Fatal("failed to update validators on the default subnet: %s", err)
|
||||
tx.vm.Ctx.Log.Fatal("failed to update Default Subnet: %s", err)
|
||||
}
|
||||
|
||||
// If this node started validating a Subnet, create the blockchains that the Subnet validates
|
||||
chains, err := tx.vm.getChains(tx.vm.DB) // all blockchains
|
||||
if err != nil {
|
||||
tx.vm.Ctx.Log.Error("couldn't get blockchains: %s", err)
|
||||
return
|
||||
}
|
||||
for subnetID, validatorIDs := range startedValidating {
|
||||
if !validatorIDs.Contains(tx.vm.Ctx.NodeID) {
|
||||
continue
|
||||
}
|
||||
for _, chain := range chains {
|
||||
if chain.SubnetID.Equals(subnetID) {
|
||||
tx.vm.createChain(chain)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Specify what the state of the chain will be if this proposal is aborted
|
||||
onAbortDB := versiondb.New(db) // state doesn't change
|
||||
|
||||
return onCommitDB, onAbortDB, updateValidators, nil, nil
|
||||
return onCommitDB, onAbortDB, onCommitFunc, nil, nil
|
||||
}
|
||||
|
||||
// InitiallyPrefersCommit returns true if the proposed time isn't after the
|
||||
|
|
|
@ -7,7 +7,6 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/ava-labs/gecko/chains"
|
||||
"github.com/ava-labs/gecko/database"
|
||||
"github.com/ava-labs/gecko/ids"
|
||||
"github.com/ava-labs/gecko/utils/crypto"
|
||||
|
@ -15,8 +14,9 @@ import (
|
|||
)
|
||||
|
||||
var (
|
||||
errInvalidVMID = errors.New("invalid VM ID")
|
||||
errFxIDsNotSortedAndUnique = errors.New("feature extensions IDs must be sorted and unique")
|
||||
errInvalidVMID = errors.New("invalid VM ID")
|
||||
errFxIDsNotSortedAndUnique = errors.New("feature extensions IDs must be sorted and unique")
|
||||
errControlSigsNotSortedAndUnique = errors.New("control signatures must be sorted and unique")
|
||||
)
|
||||
|
||||
// UnsignedCreateChainTx is an unsigned CreateChainTx
|
||||
|
@ -24,6 +24,9 @@ type UnsignedCreateChainTx struct {
|
|||
// ID of the network this blockchain exists on
|
||||
NetworkID uint32 `serialize:"true"`
|
||||
|
||||
// ID of the Subnet that validates this blockchain
|
||||
SubnetID ids.ID `serialize:"true"`
|
||||
|
||||
// Next unused nonce of account paying the transaction fee for this transaction.
|
||||
// Currently unused, as there are no tx fees.
|
||||
Nonce uint64 `serialize:"true"`
|
||||
|
@ -37,7 +40,7 @@ type UnsignedCreateChainTx struct {
|
|||
// IDs of the feature extensions running on the new chain
|
||||
FxIDs []ids.ID `serialize:"true"`
|
||||
|
||||
// Byte representation of state of the new chain
|
||||
// Byte representation of genesis state of the new chain
|
||||
GenesisData []byte `serialize:"true"`
|
||||
}
|
||||
|
||||
|
@ -45,11 +48,19 @@ type UnsignedCreateChainTx struct {
|
|||
type CreateChainTx struct {
|
||||
UnsignedCreateChainTx `serialize:"true"`
|
||||
|
||||
Sig [crypto.SECP256K1RSigLen]byte `serialize:"true"`
|
||||
// Address of the account that provides the transaction fee
|
||||
// Set in SemanticVerify
|
||||
PayerAddress ids.ShortID
|
||||
|
||||
// Signature of key whose account provides the transaction fee
|
||||
PayerSig [crypto.SECP256K1RSigLen]byte `serialize:"true"`
|
||||
|
||||
// Signatures from Subnet's control keys
|
||||
// Should not empty slice, not nil, if there are no control sigs
|
||||
ControlSigs [][crypto.SECP256K1RSigLen]byte `serialize:"true"`
|
||||
|
||||
vm *VM
|
||||
id ids.ID
|
||||
key crypto.PublicKey // public key of transaction signer
|
||||
bytes []byte
|
||||
}
|
||||
|
||||
|
@ -64,10 +75,6 @@ func (tx *CreateChainTx) initialize(vm *VM) error {
|
|||
// ID of this transaction
|
||||
func (tx *CreateChainTx) ID() ids.ID { return tx.id }
|
||||
|
||||
// Key returns the public key of the signer of this transaction
|
||||
// Precondition: tx.Verify() has been called and returned nil
|
||||
func (tx *CreateChainTx) Key() crypto.PublicKey { return tx.key }
|
||||
|
||||
// Bytes returns the byte representation of a CreateChainTx
|
||||
func (tx *CreateChainTx) Bytes() []byte { return tx.bytes }
|
||||
|
||||
|
@ -77,8 +84,8 @@ func (tx *CreateChainTx) SyntacticVerify() error {
|
|||
switch {
|
||||
case tx == nil:
|
||||
return errNilTx
|
||||
case tx.key != nil:
|
||||
return nil // Only verify the transaction once
|
||||
case !tx.PayerAddress.IsZero(): // Only verify the transaction once
|
||||
return nil
|
||||
case tx.NetworkID != tx.vm.Ctx.NetworkID: // verify the transaction is on this network
|
||||
return errWrongNetworkID
|
||||
case tx.id.IsZero():
|
||||
|
@ -87,6 +94,8 @@ func (tx *CreateChainTx) SyntacticVerify() error {
|
|||
return errInvalidVMID
|
||||
case !ids.IsSortedAndUniqueIDs(tx.FxIDs):
|
||||
return errFxIDsNotSortedAndUnique
|
||||
case !crypto.IsSortedAndUniqueSECP2561RSigs(tx.ControlSigs):
|
||||
return errControlSigsNotSortedAndUnique
|
||||
}
|
||||
|
||||
unsignedIntf := interface{}(&tx.UnsignedCreateChainTx)
|
||||
|
@ -95,11 +104,11 @@ func (tx *CreateChainTx) SyntacticVerify() error {
|
|||
return err
|
||||
}
|
||||
|
||||
key, err := tx.vm.factory.RecoverPublicKey(unsignedBytes, tx.Sig[:])
|
||||
payerKey, err := tx.vm.factory.RecoverPublicKey(unsignedBytes, tx.PayerSig[:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
tx.key = key
|
||||
tx.PayerAddress = payerKey.Address()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -125,10 +134,12 @@ func (tx *CreateChainTx) SemanticVerify(db database.Database) (func(), error) {
|
|||
}
|
||||
|
||||
// Deduct tx fee from payer's account
|
||||
account, err := tx.vm.getAccount(db, tx.Key().Address())
|
||||
account, err := tx.vm.getAccount(db, tx.PayerAddress)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// txFee is removed in account.Remove
|
||||
// TODO: Consider changing Remove to be parameterized on total amount (inc. tx fee) to remove
|
||||
account, err = account.Remove(0, tx.Nonce)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -137,20 +148,55 @@ func (tx *CreateChainTx) SemanticVerify(db database.Database) (func(), error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
// If this proposal is committed, create the new blockchain using the chain manager
|
||||
// Verify that this transaction has sufficient control signatures
|
||||
subnets, err := tx.vm.getSubnets(db) // all subnets that exist
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var subnet *CreateSubnetTx // the subnet that will validate the new chain
|
||||
for _, sn := range subnets {
|
||||
if sn.id.Equals(tx.SubnetID) {
|
||||
subnet = sn
|
||||
break
|
||||
}
|
||||
}
|
||||
if subnet == nil {
|
||||
return nil, fmt.Errorf("there is no subnet with ID %s", tx.SubnetID)
|
||||
}
|
||||
if len(tx.ControlSigs) != int(subnet.Threshold) {
|
||||
return nil, fmt.Errorf("expected tx to have %d control sigs but has %d", subnet.Threshold, len(tx.ControlSigs))
|
||||
}
|
||||
|
||||
unsignedIntf := interface{}(&tx.UnsignedCreateChainTx)
|
||||
unsignedBytes, err := Codec.Marshal(&unsignedIntf) // Byte representation of the unsigned transaction
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
unsignedBytesHash := hashing.ComputeHash256(unsignedBytes)
|
||||
|
||||
// Each element is ID of key that signed this tx
|
||||
controlIDs := make([]ids.ShortID, len(tx.ControlSigs))
|
||||
for i, sig := range tx.ControlSigs {
|
||||
key, err := tx.vm.factory.RecoverHashPublicKey(unsignedBytesHash, sig[:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
controlIDs[i] = key.Address()
|
||||
}
|
||||
|
||||
// Verify each control signature on this tx is from a control key
|
||||
controlKeys := ids.ShortSet{}
|
||||
controlKeys.Add(subnet.ControlKeys...)
|
||||
for _, controlID := range controlIDs {
|
||||
if !controlKeys.Contains(controlID) {
|
||||
return nil, errors.New("tx has control signature from key not in subnet's ControlKeys")
|
||||
}
|
||||
}
|
||||
|
||||
// If this proposal is committed and this node is a member of the
|
||||
// subnet that validates the blockchain, create the blockchain
|
||||
onAccept := func() {
|
||||
chainParams := chains.ChainParameters{
|
||||
ID: tx.ID(),
|
||||
GenesisData: tx.GenesisData,
|
||||
VMAlias: tx.VMID.String(),
|
||||
}
|
||||
for _, fxID := range tx.FxIDs {
|
||||
chainParams.FxAliases = append(chainParams.FxAliases, fxID.String())
|
||||
}
|
||||
// TODO: Not sure how else to make this not nil pointer error during tests
|
||||
if tx.vm.chainManager != nil {
|
||||
tx.vm.chainManager.CreateChain(chainParams)
|
||||
}
|
||||
tx.vm.createChain(tx)
|
||||
}
|
||||
|
||||
return onAccept, nil
|
||||
|
@ -166,10 +212,14 @@ func (chains createChainList) Bytes() []byte {
|
|||
return bytes
|
||||
}
|
||||
|
||||
func (vm *VM) newCreateChainTx(nonce uint64, genesisData []byte, vmID ids.ID, fxIDs []ids.ID, chainName string, networkID uint32, key *crypto.PrivateKeySECP256K1R) (*CreateChainTx, error) {
|
||||
func (vm *VM) newCreateChainTx(nonce uint64, subnetID ids.ID, genesisData []byte,
|
||||
vmID ids.ID, fxIDs []ids.ID, chainName string, networkID uint32,
|
||||
controlKeys []*crypto.PrivateKeySECP256K1R,
|
||||
payerKey *crypto.PrivateKeySECP256K1R) (*CreateChainTx, error) {
|
||||
tx := &CreateChainTx{
|
||||
UnsignedCreateChainTx: UnsignedCreateChainTx{
|
||||
NetworkID: networkID,
|
||||
SubnetID: subnetID,
|
||||
Nonce: nonce,
|
||||
GenesisData: genesisData,
|
||||
VMID: vmID,
|
||||
|
@ -178,17 +228,33 @@ func (vm *VM) newCreateChainTx(nonce uint64, genesisData []byte, vmID ids.ID, fx
|
|||
},
|
||||
}
|
||||
|
||||
// Generate byte repr. of unsigned transaction
|
||||
unsignedIntf := interface{}(&tx.UnsignedCreateChainTx)
|
||||
unsignedBytes, err := Codec.Marshal(&unsignedIntf) // Byte repr. of unsigned transaction
|
||||
unsignedBytes, err := Codec.Marshal(&unsignedIntf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
unsignedBytesHash := hashing.ComputeHash256(unsignedBytes)
|
||||
|
||||
// Sign the tx with control keys
|
||||
tx.ControlSigs = make([][crypto.SECP256K1RSigLen]byte, len(controlKeys))
|
||||
for i, key := range controlKeys {
|
||||
sig, err := key.SignHash(unsignedBytesHash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
copy(tx.ControlSigs[i][:], sig)
|
||||
}
|
||||
|
||||
sig, err := key.Sign(unsignedBytes)
|
||||
// Sort the control signatures
|
||||
crypto.SortSECP2561RSigs(tx.ControlSigs)
|
||||
|
||||
// Sign with the payer key
|
||||
payerSig, err := payerKey.Sign(unsignedBytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
copy(tx.Sig[:], sig)
|
||||
copy(tx.PayerSig[:], payerSig)
|
||||
|
||||
return tx, tx.initialize(vm)
|
||||
}
|
||||
|
|
|
@ -6,8 +6,8 @@ package platformvm
|
|||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/ava-labs/gecko/database/versiondb"
|
||||
"github.com/ava-labs/gecko/ids"
|
||||
"github.com/ava-labs/gecko/utils/crypto"
|
||||
"github.com/ava-labs/gecko/vms/avm"
|
||||
)
|
||||
|
||||
|
@ -24,18 +24,19 @@ func TestCreateChainTxSyntacticVerify(t *testing.T) {
|
|||
// Case 2: network ID is wrong
|
||||
tx, err := vm.newCreateChainTx(
|
||||
defaultNonce+1,
|
||||
testSubnet1.id,
|
||||
nil,
|
||||
avm.ID,
|
||||
nil,
|
||||
"chain name",
|
||||
testNetworkID+1,
|
||||
[]*crypto.PrivateKeySECP256K1R{testSubnet1ControlKeys[0], testSubnet1ControlKeys[1]},
|
||||
defaultKey,
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = tx.SyntacticVerify()
|
||||
t.Log(err)
|
||||
if err == nil {
|
||||
t.Fatal("should've errored because network ID is wrong")
|
||||
}
|
||||
|
@ -43,11 +44,13 @@ func TestCreateChainTxSyntacticVerify(t *testing.T) {
|
|||
// case 3: tx ID is empty
|
||||
tx, err = vm.newCreateChainTx(
|
||||
defaultNonce+1,
|
||||
testSubnet1.id,
|
||||
nil,
|
||||
avm.ID,
|
||||
nil,
|
||||
"chain name",
|
||||
testNetworkID,
|
||||
[]*crypto.PrivateKeySECP256K1R{testSubnet1ControlKeys[0], testSubnet1ControlKeys[1]},
|
||||
defaultKey,
|
||||
)
|
||||
if err != nil {
|
||||
|
@ -61,11 +64,13 @@ func TestCreateChainTxSyntacticVerify(t *testing.T) {
|
|||
// Case 4: vm ID is empty
|
||||
tx, err = vm.newCreateChainTx(
|
||||
defaultNonce+1,
|
||||
testSubnet1.id,
|
||||
nil,
|
||||
avm.ID,
|
||||
nil,
|
||||
"chain name",
|
||||
testNetworkID,
|
||||
[]*crypto.PrivateKeySECP256K1R{testSubnet1ControlKeys[0], testSubnet1ControlKeys[1]},
|
||||
defaultKey,
|
||||
)
|
||||
if err != nil {
|
||||
|
@ -75,62 +80,189 @@ func TestCreateChainTxSyntacticVerify(t *testing.T) {
|
|||
if err := tx.SyntacticVerify(); err == nil {
|
||||
t.Fatal("should've errored because tx ID is empty")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSemanticVerify(t *testing.T) {
|
||||
vm := defaultVM()
|
||||
|
||||
// create a tx
|
||||
tx, err := vm.newCreateChainTx(
|
||||
// Case 5: Control sigs not sorted
|
||||
tx, err = vm.newCreateChainTx(
|
||||
defaultNonce+1,
|
||||
testSubnet1.id,
|
||||
nil,
|
||||
avm.ID,
|
||||
nil,
|
||||
"chain name",
|
||||
testNetworkID,
|
||||
[]*crypto.PrivateKeySECP256K1R{testSubnet1ControlKeys[0], testSubnet1ControlKeys[1]},
|
||||
defaultKey,
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// Reverse signature order
|
||||
tx.ControlSigs[0], tx.ControlSigs[1] = tx.ControlSigs[1], tx.ControlSigs[0]
|
||||
if err := tx.SyntacticVerify(); err == nil {
|
||||
t.Fatal("should've errored because control sigs not sorted")
|
||||
}
|
||||
|
||||
// Case 6: Control sigs not unique
|
||||
tx, err = vm.newCreateChainTx(
|
||||
defaultNonce+1,
|
||||
testSubnet1.id,
|
||||
nil,
|
||||
avm.ID,
|
||||
nil,
|
||||
"chain name",
|
||||
testNetworkID,
|
||||
[]*crypto.PrivateKeySECP256K1R{testSubnet1ControlKeys[0], testSubnet1ControlKeys[1]},
|
||||
defaultKey,
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
tx.ControlSigs[0] = tx.ControlSigs[1]
|
||||
if err := tx.SyntacticVerify(); err == nil {
|
||||
t.Fatal("should've errored because control sigs not unique")
|
||||
}
|
||||
|
||||
// Case 7: Valid tx passes syntactic verification
|
||||
tx, err = vm.newCreateChainTx(
|
||||
defaultNonce+1,
|
||||
testSubnet1.id,
|
||||
nil,
|
||||
avm.ID,
|
||||
nil,
|
||||
"chain name",
|
||||
testNetworkID,
|
||||
[]*crypto.PrivateKeySECP256K1R{testSubnet1ControlKeys[0], testSubnet1ControlKeys[1]},
|
||||
defaultKey,
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("should have passed verification but got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure SemanticVerify fails when there are not enough control sigs
|
||||
func TestCreateChainTxInsufficientControlSigs(t *testing.T) {
|
||||
vm := defaultVM()
|
||||
|
||||
// Case 1: No control sigs (2 are needed)
|
||||
tx, err := vm.newCreateChainTx(
|
||||
defaultNonce+1,
|
||||
testSubnet1.id,
|
||||
nil,
|
||||
avm.ID,
|
||||
nil,
|
||||
"chain name",
|
||||
testNetworkID,
|
||||
nil,
|
||||
defaultKey,
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
newDB := versiondb.New(vm.DB)
|
||||
|
||||
_, err = tx.SemanticVerify(newDB)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
_, err = tx.SemanticVerify(vm.DB)
|
||||
if err == nil {
|
||||
t.Fatal("should have errored because there are no control sigs")
|
||||
}
|
||||
|
||||
chains, err := vm.getChains(newDB)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, c := range chains {
|
||||
if c.ID().Equals(tx.ID()) {
|
||||
return
|
||||
}
|
||||
}
|
||||
t.Fatalf("Should have added the chain to the set of chains")
|
||||
}
|
||||
|
||||
func TestSemanticVerifyAlreadyExisting(t *testing.T) {
|
||||
vm := defaultVM()
|
||||
|
||||
// create a tx
|
||||
tx, err := vm.newCreateChainTx(
|
||||
// Case 2: 1 control sig (2 are needed)
|
||||
tx, err = vm.newCreateChainTx(
|
||||
defaultNonce+1,
|
||||
testSubnet1.id,
|
||||
nil,
|
||||
avm.ID,
|
||||
nil,
|
||||
"chain name",
|
||||
testNetworkID,
|
||||
[]*crypto.PrivateKeySECP256K1R{testSubnet1ControlKeys[0]},
|
||||
defaultKey,
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// put the chain in existing chain
|
||||
_, err = tx.SemanticVerify(vm.DB)
|
||||
if err == nil {
|
||||
t.Fatal("should have errored because there are no control sigs")
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure SemanticVerify fails when an incorrect control signature is given
|
||||
func TestCreateChainTxWrongControlSig(t *testing.T) {
|
||||
vm := defaultVM()
|
||||
|
||||
// Generate new, random key to sign tx with
|
||||
factory := crypto.FactorySECP256K1R{}
|
||||
key, err := factory.NewPrivateKey()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
tx, err := vm.newCreateChainTx(
|
||||
defaultNonce+1,
|
||||
testSubnet1.id,
|
||||
nil,
|
||||
avm.ID,
|
||||
nil,
|
||||
"chain name",
|
||||
testNetworkID,
|
||||
[]*crypto.PrivateKeySECP256K1R{testSubnet1ControlKeys[0], key.(*crypto.PrivateKeySECP256K1R)},
|
||||
defaultKey,
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
_, err = tx.SemanticVerify(vm.DB)
|
||||
if err == nil {
|
||||
t.Fatal("should have errored because incorrect control sig given")
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure SemanticVerify fails when the Subnet the blockchain specifies as
|
||||
// its validator set doesn't exist
|
||||
func TestCreateChainTxNoSuchSubnet(t *testing.T) {
|
||||
vm := defaultVM()
|
||||
|
||||
tx, err := vm.newCreateChainTx(
|
||||
defaultNonce+1,
|
||||
ids.NewID([32]byte{1, 9, 124, 11, 20}), // pick some random ID for subnet
|
||||
nil,
|
||||
avm.ID,
|
||||
nil,
|
||||
"chain name",
|
||||
testNetworkID,
|
||||
[]*crypto.PrivateKeySECP256K1R{testSubnet1ControlKeys[0], testSubnet1ControlKeys[1]},
|
||||
defaultKey,
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_, err = tx.SemanticVerify(vm.DB)
|
||||
if err == nil {
|
||||
t.Fatal("should have errored because Subnet doesn't exist")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateChainTxAlreadyExists(t *testing.T) {
|
||||
vm := defaultVM()
|
||||
|
||||
// create a tx
|
||||
tx, err := vm.newCreateChainTx(
|
||||
defaultNonce+1,
|
||||
testSubnet1.id,
|
||||
nil,
|
||||
avm.ID,
|
||||
nil,
|
||||
"chain name",
|
||||
testNetworkID,
|
||||
[]*crypto.PrivateKeySECP256K1R{testSubnet1ControlKeys[0], testSubnet1ControlKeys[1]},
|
||||
defaultKey,
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// put the chain in existing chain list
|
||||
if err := vm.putChains(vm.DB, []*CreateChainTx{tx}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -140,3 +272,29 @@ func TestSemanticVerifyAlreadyExisting(t *testing.T) {
|
|||
t.Fatalf("should have failed because there is already a chain with ID %s", tx.id)
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure valid tx passes semanticVerify
|
||||
func TestCreateChainTxValid(t *testing.T) {
|
||||
vm := defaultVM()
|
||||
|
||||
// create a valid tx
|
||||
tx, err := vm.newCreateChainTx(
|
||||
defaultNonce+1,
|
||||
testSubnet1.id,
|
||||
nil,
|
||||
avm.ID,
|
||||
nil,
|
||||
"chain name",
|
||||
testNetworkID,
|
||||
[]*crypto.PrivateKeySECP256K1R{testSubnet1ControlKeys[0], testSubnet1ControlKeys[1]},
|
||||
defaultKey,
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
_, err = tx.SemanticVerify(vm.DB)
|
||||
if err != nil {
|
||||
t.Fatalf("expected tx to pass verification but got error: %v", err)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,8 +8,8 @@ import (
|
|||
"fmt"
|
||||
|
||||
"github.com/ava-labs/gecko/database"
|
||||
|
||||
"github.com/ava-labs/gecko/ids"
|
||||
"github.com/ava-labs/gecko/snow/validators"
|
||||
"github.com/ava-labs/gecko/utils/crypto"
|
||||
"github.com/ava-labs/gecko/utils/hashing"
|
||||
)
|
||||
|
@ -17,8 +17,10 @@ import (
|
|||
const maxThreshold = 25
|
||||
|
||||
var (
|
||||
errThresholdExceedsKeysLen = errors.New("threshold must be no more than number of control keys")
|
||||
errThresholdTooHigh = fmt.Errorf("threshold can't be greater than %d", maxThreshold)
|
||||
errThresholdExceedsKeysLen = errors.New("threshold must be no more than number of control keys")
|
||||
errThresholdTooHigh = fmt.Errorf("threshold can't be greater than %d", maxThreshold)
|
||||
errControlKeysNotSortedAndUnique = errors.New("control keys must be sorted and unique")
|
||||
errUnneededKeys = errors.New("subnets shouldn't have keys if the threshold is 0")
|
||||
)
|
||||
|
||||
// UnsignedCreateSubnetTx is an unsigned proposal to create a new subnet
|
||||
|
@ -41,11 +43,8 @@ type UnsignedCreateSubnetTx struct {
|
|||
type CreateSubnetTx struct {
|
||||
UnsignedCreateSubnetTx `serialize:"true"`
|
||||
|
||||
// The VM this tx exists within
|
||||
vm *VM
|
||||
|
||||
// ID is this transaction's ID
|
||||
id ids.ID
|
||||
// Signature on the UnsignedCreateSubnetTx's byte repr
|
||||
Sig [crypto.SECP256K1RSigLen]byte `serialize:"true"`
|
||||
|
||||
// The public key that signed this transaction
|
||||
// The transaction fee will be paid from the corresponding account
|
||||
|
@ -53,14 +52,17 @@ type CreateSubnetTx struct {
|
|||
// [key] is non-nil iff this tx is valid
|
||||
key crypto.PublicKey
|
||||
|
||||
// Signature on the UnsignedCreateSubnetTx's byte repr
|
||||
Sig [crypto.SECP256K1RSigLen]byte `serialize:"true"`
|
||||
// The VM this tx exists within
|
||||
vm *VM
|
||||
|
||||
// ID is this transaction's ID
|
||||
id ids.ID
|
||||
|
||||
// Byte representation of this transaction (including signature)
|
||||
bytes []byte
|
||||
}
|
||||
|
||||
// ID returns the ID of this tx
|
||||
// ID returns the ID of this transaction
|
||||
func (tx *CreateSubnetTx) ID() ids.ID { return tx.id }
|
||||
|
||||
// SyntacticVerify nil iff [tx] is syntactically valid.
|
||||
|
@ -77,6 +79,12 @@ func (tx *CreateSubnetTx) SyntacticVerify() error {
|
|||
return errWrongNetworkID
|
||||
case tx.Threshold > uint16(len(tx.ControlKeys)):
|
||||
return errThresholdExceedsKeysLen
|
||||
case tx.Threshold > maxThreshold:
|
||||
return errThresholdTooHigh
|
||||
case tx.Threshold == 0 && len(tx.ControlKeys) > 0:
|
||||
return errUnneededKeys
|
||||
case !ids.IsSortedAndUniqueShortIDs(tx.ControlKeys):
|
||||
return errControlKeysNotSortedAndUnique
|
||||
}
|
||||
|
||||
// Byte representation of the unsigned transaction
|
||||
|
@ -107,12 +115,6 @@ func (tx *CreateSubnetTx) SemanticVerify(db database.Database) (func(), error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, subnet := range subnets {
|
||||
if subnet.id.Equals(tx.id) {
|
||||
return nil, fmt.Errorf("there is already a subnet with ID %s", tx.id)
|
||||
}
|
||||
}
|
||||
subnets = append(subnets, tx) // add new subnet
|
||||
if err := tx.vm.putSubnets(db, subnets); err != nil {
|
||||
return nil, err
|
||||
|
@ -131,7 +133,12 @@ func (tx *CreateSubnetTx) SemanticVerify(db database.Database) (func(), error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
// Register new subnet in validator manager
|
||||
onAccept := func() {
|
||||
tx.vm.validators.PutValidatorSet(tx.id, validators.NewSet())
|
||||
}
|
||||
|
||||
return onAccept, nil
|
||||
}
|
||||
|
||||
// Bytes returns the byte representation of [tx]
|
||||
|
@ -159,10 +166,11 @@ func (tx *CreateSubnetTx) initialize(vm *VM) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// [controlKeys] must be unique. They will be sorted by this method.
|
||||
// If [controlKeys] is nil, [tx.Controlkeys] will be an empty list.
|
||||
func (vm *VM) newCreateSubnetTx(networkID uint32, nonce uint64, controlKeys []ids.ShortID,
|
||||
threshold uint16, payerKey *crypto.PrivateKeySECP256K1R,
|
||||
) (*CreateSubnetTx, error) {
|
||||
|
||||
tx := &CreateSubnetTx{UnsignedCreateSubnetTx: UnsignedCreateSubnetTx{
|
||||
NetworkID: networkID,
|
||||
Nonce: nonce,
|
||||
|
@ -170,6 +178,17 @@ func (vm *VM) newCreateSubnetTx(networkID uint32, nonce uint64, controlKeys []id
|
|||
Threshold: threshold,
|
||||
}}
|
||||
|
||||
if threshold == 0 && len(tx.ControlKeys) > 0 {
|
||||
return nil, errUnneededKeys
|
||||
}
|
||||
|
||||
// Sort control keys
|
||||
ids.SortShortIDs(tx.ControlKeys)
|
||||
// Ensure control keys are unique
|
||||
if !ids.IsSortedAndUniqueShortIDs(tx.ControlKeys) {
|
||||
return nil, errControlKeysNotSortedAndUnique
|
||||
}
|
||||
|
||||
unsignedIntf := interface{}(&tx.UnsignedCreateSubnetTx)
|
||||
unsignedBytes, err := Codec.Marshal(&unsignedIntf)
|
||||
if err != nil {
|
||||
|
|
|
@ -183,7 +183,7 @@ func (vm *VM) newExportTx(nonce uint64, networkID uint32, outs []*ava.Transferab
|
|||
return nil, err
|
||||
}
|
||||
|
||||
sig, err := key.Sign(unsignedBytes)
|
||||
sig, err := from.Sign(unsignedBytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -16,18 +16,20 @@ var (
|
|||
|
||||
// Factory can create new instances of the Platform Chain
|
||||
type Factory struct {
|
||||
ChainManager chains.Manager
|
||||
Validators validators.Manager
|
||||
AVA ids.ID
|
||||
AVM ids.ID
|
||||
ChainManager chains.Manager
|
||||
Validators validators.Manager
|
||||
StakingEnabled bool
|
||||
AVA ids.ID
|
||||
AVM ids.ID
|
||||
}
|
||||
|
||||
// New returns a new instance of the Platform Chain
|
||||
func (f *Factory) New() interface{} {
|
||||
return &VM{
|
||||
chainManager: f.ChainManager,
|
||||
validators: f.Validators,
|
||||
ava: f.AVA,
|
||||
avm: f.AVM,
|
||||
chainManager: f.ChainManager,
|
||||
validators: f.Validators,
|
||||
stakingEnabled: f.StakingEnabled,
|
||||
ava: f.AVA,
|
||||
avm: f.AVM,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -231,7 +231,7 @@ func (vm *VM) newImportTx(nonce uint64, networkID uint32, ins []*ava.Transferabl
|
|||
tx := &ImportTx{UnsignedImportTx: UnsignedImportTx{
|
||||
NetworkID: networkID,
|
||||
Nonce: nonce,
|
||||
Account: key.PublicKey().Address(),
|
||||
Account: to.PublicKey().Address(),
|
||||
Ins: ins,
|
||||
}}
|
||||
|
||||
|
@ -258,7 +258,7 @@ func (vm *VM) newImportTx(nonce uint64, networkID uint32, ins []*ava.Transferabl
|
|||
tx.Creds = append(tx.Creds, cred)
|
||||
}
|
||||
|
||||
sig, err := key.SignHash(hash)
|
||||
sig, err := to.SignHash(hash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -8,9 +8,6 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
|
||||
"github.com/gorilla/rpc/v2/json2"
|
||||
|
||||
"github.com/ava-labs/gecko/database"
|
||||
"github.com/ava-labs/gecko/ids"
|
||||
|
@ -19,39 +16,26 @@ import (
|
|||
"github.com/ava-labs/gecko/utils/hashing"
|
||||
"github.com/ava-labs/gecko/utils/json"
|
||||
"github.com/ava-labs/gecko/utils/math"
|
||||
"github.com/ava-labs/gecko/vms/avm"
|
||||
"github.com/ava-labs/gecko/vms/components/ava"
|
||||
"github.com/ava-labs/gecko/vms/secp256k1fx"
|
||||
)
|
||||
|
||||
var (
|
||||
errMissingDecisionBlock = errors.New("should have a decision block within the past two blocks")
|
||||
errParsingID = errors.New("error parsing ID")
|
||||
errGetAccount = errors.New("error retrieving account information")
|
||||
errGetAccounts = errors.New("error getting accounts controlled by specified user")
|
||||
errGetUser = errors.New("error while getting user. Does user exist?")
|
||||
errNoMethodWithGenesis = errors.New("no method was provided but genesis data was provided")
|
||||
errCreatingTransaction = errors.New("problem while creating transaction")
|
||||
errNoDestination = errors.New("call is missing field 'stakeDestination'")
|
||||
errNoSource = errors.New("call is missing field 'stakeSource'")
|
||||
errGetStakeSource = errors.New("couldn't get account specified in 'stakeSource'")
|
||||
errMissingDecisionBlock = errors.New("should have a decision block within the past two blocks")
|
||||
errParsingID = errors.New("error parsing ID")
|
||||
errGetAccount = errors.New("error retrieving account information")
|
||||
errGetAccounts = errors.New("error getting accounts controlled by specified user")
|
||||
errGetUser = errors.New("error while getting user. Does user exist?")
|
||||
errNoMethodWithGenesis = errors.New("no method was provided but genesis data was provided")
|
||||
errCreatingTransaction = errors.New("problem while creating transaction")
|
||||
errNoDestination = errors.New("call is missing field 'stakeDestination'")
|
||||
errNoSource = errors.New("call is missing field 'stakeSource'")
|
||||
errGetStakeSource = errors.New("couldn't get account specified in 'stakeSource'")
|
||||
errNoBlockchainWithAlias = errors.New("there is no blockchain with the specified alias")
|
||||
errDSCantValidate = errors.New("new blockchain can't be validated by default Subnet")
|
||||
)
|
||||
|
||||
var key *crypto.PrivateKeySECP256K1R
|
||||
|
||||
func init() {
|
||||
cb58 := formatting.CB58{}
|
||||
err := cb58.FromString("24jUJ9vZexUM6expyMcT48LBx27k1m7xpraoV62oSQAHdziao5")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
factory := crypto.FactorySECP256K1R{}
|
||||
pk, err := factory.ToPrivateKey(cb58.Bytes)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
key = pk.(*crypto.PrivateKeySECP256K1R)
|
||||
}
|
||||
|
||||
// Service defines the API calls that can be made to the platform chain
|
||||
type Service struct{ vm *VM }
|
||||
|
||||
|
@ -319,7 +303,7 @@ type ListAccountsReply struct {
|
|||
|
||||
// ListAccounts lists all of the accounts controlled by [args.Username]
|
||||
func (service *Service) ListAccounts(_ *http.Request, args *ListAccountsArgs, reply *ListAccountsReply) error {
|
||||
service.vm.Ctx.Log.Debug("platform.listAccounts called for user '%s'", args.Username)
|
||||
service.vm.Ctx.Log.Debug("listAccounts called for user '%s'", args.Username)
|
||||
|
||||
// db holds the user's info that pertains to the Platform Chain
|
||||
userDB, err := service.vm.Ctx.Keystore.GetDatabase(args.Username, args.Password)
|
||||
|
@ -382,7 +366,7 @@ type CreateAccountReply struct {
|
|||
// The account's ID is [privKey].PublicKey().Address(), where [privKey] is a
|
||||
// private key controlled by the user.
|
||||
func (service *Service) CreateAccount(_ *http.Request, args *CreateAccountArgs, reply *CreateAccountReply) error {
|
||||
service.vm.Ctx.Log.Debug("platform.createAccount called for user '%s'", args.Username)
|
||||
service.vm.Ctx.Log.Debug("createAccount called for user '%s'", args.Username)
|
||||
|
||||
// userDB holds the user's info that pertains to the Platform Chain
|
||||
userDB, err := service.vm.Ctx.Keystore.GetDatabase(args.Username, args.Password)
|
||||
|
@ -452,7 +436,7 @@ type AddDefaultSubnetValidatorArgs struct {
|
|||
// AddDefaultSubnetValidator returns an unsigned transaction to add a validator to the default subnet
|
||||
// The returned unsigned transaction should be signed using Sign()
|
||||
func (service *Service) AddDefaultSubnetValidator(_ *http.Request, args *AddDefaultSubnetValidatorArgs, reply *CreateTxResponse) error {
|
||||
service.vm.Ctx.Log.Debug("platform.AddDefaultSubnetValidator called")
|
||||
service.vm.Ctx.Log.Debug("AddDefaultSubnetValidator called")
|
||||
|
||||
if args.ID.IsZero() { // If ID unspecified, use this node's ID as validator ID
|
||||
args.ID = service.vm.Ctx.NodeID
|
||||
|
@ -497,7 +481,7 @@ type AddDefaultSubnetDelegatorArgs struct {
|
|||
// to the default subnet
|
||||
// The returned unsigned transaction should be signed using Sign()
|
||||
func (service *Service) AddDefaultSubnetDelegator(_ *http.Request, args *AddDefaultSubnetDelegatorArgs, reply *CreateTxResponse) error {
|
||||
service.vm.Ctx.Log.Debug("platform.AddDefaultSubnetDelegator called")
|
||||
service.vm.Ctx.Log.Debug("AddDefaultSubnetDelegator called")
|
||||
|
||||
if args.ID.IsZero() { // If ID unspecified, use this node's ID as validator ID
|
||||
args.ID = service.vm.Ctx.NodeID
|
||||
|
@ -679,7 +663,7 @@ type SignResponse struct {
|
|||
|
||||
// Sign [args.bytes]
|
||||
func (service *Service) Sign(_ *http.Request, args *SignArgs, reply *SignResponse) error {
|
||||
service.vm.Ctx.Log.Debug("platform.sign called")
|
||||
service.vm.Ctx.Log.Debug("sign called")
|
||||
|
||||
// Get the key of the Signer
|
||||
db, err := service.vm.Ctx.Keystore.GetDatabase(args.Username, args.Password)
|
||||
|
@ -710,10 +694,12 @@ func (service *Service) Sign(_ *http.Request, args *SignArgs, reply *SignRespons
|
|||
genTx.Tx, err = service.signAddNonDefaultSubnetValidatorTx(tx, key)
|
||||
case *CreateSubnetTx:
|
||||
genTx.Tx, err = service.signCreateSubnetTx(tx, key)
|
||||
case *CreateChainTx:
|
||||
genTx.Tx, err = service.signCreateChainTx(tx, key)
|
||||
case *ExportTx:
|
||||
genTx.Tx, err = service.signExportTx(tx, key)
|
||||
default:
|
||||
err = errors.New("Could not parse given tx. Must be one of: addDefaultSubnetValidatorTx, addNonDefaultSubnetValidatorTx, createSubnetTx")
|
||||
err = errors.New("Could not parse given tx")
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -725,7 +711,7 @@ func (service *Service) Sign(_ *http.Request, args *SignArgs, reply *SignRespons
|
|||
|
||||
// Sign [unsigned] with [key]
|
||||
func (service *Service) signAddDefaultSubnetValidatorTx(tx *addDefaultSubnetValidatorTx, key *crypto.PrivateKeySECP256K1R) (*addDefaultSubnetValidatorTx, error) {
|
||||
service.vm.Ctx.Log.Debug("platform.signAddDefaultSubnetValidatorTx called")
|
||||
service.vm.Ctx.Log.Debug("signAddDefaultSubnetValidatorTx called")
|
||||
|
||||
// TODO: Should we check if tx is already signed?
|
||||
unsignedIntf := interface{}(&tx.UnsignedAddDefaultSubnetValidatorTx)
|
||||
|
@ -748,7 +734,7 @@ func (service *Service) signAddDefaultSubnetValidatorTx(tx *addDefaultSubnetVali
|
|||
|
||||
// Sign [unsigned] with [key]
|
||||
func (service *Service) signAddDefaultSubnetDelegatorTx(tx *addDefaultSubnetDelegatorTx, key *crypto.PrivateKeySECP256K1R) (*addDefaultSubnetDelegatorTx, error) {
|
||||
service.vm.Ctx.Log.Debug("platform.signAddDefaultSubnetValidatorTx called")
|
||||
service.vm.Ctx.Log.Debug("signAddDefaultSubnetValidatorTx called")
|
||||
|
||||
// TODO: Should we check if tx is already signed?
|
||||
unsignedIntf := interface{}(&tx.UnsignedAddDefaultSubnetDelegatorTx)
|
||||
|
@ -771,7 +757,7 @@ func (service *Service) signAddDefaultSubnetDelegatorTx(tx *addDefaultSubnetDele
|
|||
|
||||
// Sign [xt] with [key]
|
||||
func (service *Service) signCreateSubnetTx(tx *CreateSubnetTx, key *crypto.PrivateKeySECP256K1R) (*CreateSubnetTx, error) {
|
||||
service.vm.Ctx.Log.Debug("platform.signAddDefaultSubnetValidatorTx called")
|
||||
service.vm.Ctx.Log.Debug("signAddDefaultSubnetValidatorTx called")
|
||||
|
||||
// TODO: Should we check if tx is already signed?
|
||||
unsignedIntf := interface{}(&tx.UnsignedCreateSubnetTx)
|
||||
|
@ -822,7 +808,7 @@ func (service *Service) signExportTx(tx *ExportTx, key *crypto.PrivateKeySECP256
|
|||
// Sorts tx.ControlSigs before returning
|
||||
// Assumes each element of tx.ControlSigs is actually a signature, not just empty bytes
|
||||
func (service *Service) signAddNonDefaultSubnetValidatorTx(tx *addNonDefaultSubnetValidatorTx, key *crypto.PrivateKeySECP256K1R) (*addNonDefaultSubnetValidatorTx, error) {
|
||||
service.vm.Ctx.Log.Debug("platform.signAddNonDefaultSubnetValidatorTx called")
|
||||
service.vm.Ctx.Log.Debug("signAddNonDefaultSubnetValidatorTx called")
|
||||
|
||||
// Compute the byte repr. of the unsigned tx and the signature of [key] over it
|
||||
unsignedIntf := interface{}(&tx.UnsignedAddNonDefaultSubnetValidatorTx)
|
||||
|
@ -1003,6 +989,59 @@ func (service *Service) CreateImportTx(_ *http.Request, args *CreateImportTxArgs
|
|||
return nil
|
||||
}
|
||||
|
||||
// Signs an unsigned or partially signed CreateChainTx with [key]
|
||||
// If [key] is a control key for the subnet and there is an empty spot in tx.ControlSigs, signs there
|
||||
// If [key] is a control key for the subnet and there is no empty spot in tx.ControlSigs, signs as payer
|
||||
// If [key] is not a control key, sign as payer (account controlled by [key] pays the tx fee)
|
||||
// Sorts tx.ControlSigs before returning
|
||||
// Assumes each element of tx.ControlSigs is actually a signature, not just empty bytes
|
||||
func (service *Service) signCreateChainTx(tx *CreateChainTx, key *crypto.PrivateKeySECP256K1R) (*CreateChainTx, error) {
|
||||
service.vm.Ctx.Log.Debug("signCreateChainTx called")
|
||||
|
||||
// Compute the byte repr. of the unsigned tx and the signature of [key] over it
|
||||
unsignedIntf := interface{}(&tx.UnsignedCreateChainTx)
|
||||
unsignedTxBytes, err := Codec.Marshal(&unsignedIntf)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error serializing unsigned tx: %v", err)
|
||||
}
|
||||
sig, err := key.Sign(unsignedTxBytes)
|
||||
if err != nil {
|
||||
return nil, errors.New("error while signing")
|
||||
}
|
||||
if len(sig) != crypto.SECP256K1RSigLen {
|
||||
return nil, fmt.Errorf("expected signature to be length %d but was length %d", crypto.SECP256K1RSigLen, len(sig))
|
||||
}
|
||||
|
||||
// Get information about the subnet
|
||||
subnet, err := service.vm.getSubnet(service.vm.DB, tx.SubnetID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("problem getting subnet information: %v", err)
|
||||
}
|
||||
|
||||
// Find the location at which [key] should put its signature.
|
||||
// If [key] is a control key for this subnet and there is an empty spot in tx.ControlSigs, sign there
|
||||
// If [key] is a control key for this subnet and there is no empty spot in tx.ControlSigs, sign as payer
|
||||
// If [key] is not a control key, sign as payer (account controlled by [key] pays the tx fee)
|
||||
controlKeySet := ids.ShortSet{}
|
||||
controlKeySet.Add(subnet.ControlKeys...)
|
||||
isControlKey := controlKeySet.Contains(key.PublicKey().Address())
|
||||
|
||||
payerSigEmpty := tx.PayerSig == [crypto.SECP256K1RSigLen]byte{} // true if no key has signed to pay the tx fee
|
||||
|
||||
if isControlKey && len(tx.ControlSigs) != int(subnet.Threshold) { // Sign as controlSig
|
||||
tx.ControlSigs = append(tx.ControlSigs, [crypto.SECP256K1RSigLen]byte{})
|
||||
copy(tx.ControlSigs[len(tx.ControlSigs)-1][:], sig)
|
||||
} else if payerSigEmpty { // sign as payer
|
||||
copy(tx.PayerSig[:], sig)
|
||||
} else {
|
||||
return nil, errors.New("no place for key to sign")
|
||||
}
|
||||
|
||||
crypto.SortSECP2561RSigs(tx.ControlSigs)
|
||||
|
||||
return tx, nil
|
||||
}
|
||||
|
||||
// IssueTxArgs are the arguments to IssueTx
|
||||
type IssueTxArgs struct {
|
||||
// Tx being sent to the network
|
||||
|
@ -1017,6 +1056,8 @@ type IssueTxResponse struct {
|
|||
|
||||
// IssueTx issues the transaction [args.Tx] to the network
|
||||
func (service *Service) IssueTx(_ *http.Request, args *IssueTxArgs, response *IssueTxResponse) error {
|
||||
service.vm.Ctx.Log.Debug("issueTx called")
|
||||
|
||||
genTx := genericTx{}
|
||||
if err := Codec.Unmarshal(args.Tx.Bytes, &genTx); err != nil {
|
||||
return err
|
||||
|
@ -1057,6 +1098,9 @@ func (service *Service) IssueTx(_ *http.Request, args *IssueTxArgs, response *Is
|
|||
|
||||
// CreateBlockchainArgs is the arguments for calling CreateBlockchain
|
||||
type CreateBlockchainArgs struct {
|
||||
// ID of Subnet that validates the new blockchain
|
||||
SubnetID ids.ID `json:"subnetID"`
|
||||
|
||||
// ID of the VM the new blockchain is running
|
||||
VMID string `json:"vmID"`
|
||||
|
||||
|
@ -1066,26 +1110,18 @@ type CreateBlockchainArgs struct {
|
|||
// Human-readable name for the new blockchain, not necessarily unique
|
||||
Name string `json:"name"`
|
||||
|
||||
// To generate the byte representation of the genesis data for this blockchain,
|
||||
// a POST request with body [GenesisData] is made to the API method whose name is [Method], whose
|
||||
// endpoint is [Endpoint]. See Platform Chain documentation for more info and examples.
|
||||
Method string `json:"method"`
|
||||
Endpoint string `json:"endpoint"`
|
||||
GenesisData interface{} `json:"genesisData"`
|
||||
// Next unused nonce of the account paying the transaction fee
|
||||
PayerNonce json.Uint64 `json:"payerNonce"`
|
||||
|
||||
// Genesis state of the blockchain being created
|
||||
GenesisData formatting.CB58 `json:"genesisData"`
|
||||
}
|
||||
|
||||
// CreateGenesisReply is the reply from a call to CreateGenesis
|
||||
type CreateGenesisReply struct {
|
||||
Bytes formatting.CB58 `json:"bytes"`
|
||||
}
|
||||
// CreateBlockchain returns an unsigned transaction to create a new blockchain
|
||||
// Must be signed with the Subnet's control keys and with a key that pays the transaction fee before issuance
|
||||
func (service *Service) CreateBlockchain(_ *http.Request, args *CreateBlockchainArgs, response *CreateTxResponse) error {
|
||||
service.vm.Ctx.Log.Debug("createBlockchain called")
|
||||
|
||||
// CreateBlockchainReply is the reply from calling CreateBlockchain
|
||||
type CreateBlockchainReply struct {
|
||||
BlockchainID ids.ID `json:"blockchainID"`
|
||||
}
|
||||
|
||||
// CreateBlockchain issues a transaction to the network to create a new blockchain
|
||||
func (service *Service) CreateBlockchain(_ *http.Request, args *CreateBlockchainArgs, reply *CreateBlockchainReply) error {
|
||||
vmID, err := service.vm.chainManager.LookupVM(args.VMID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("no VM with ID '%s' found", args.VMID)
|
||||
|
@ -1099,48 +1135,43 @@ func (service *Service) CreateBlockchain(_ *http.Request, args *CreateBlockchain
|
|||
}
|
||||
fxIDs = append(fxIDs, fxID)
|
||||
}
|
||||
|
||||
genesisBytes := []byte(nil)
|
||||
if args.Method != "" {
|
||||
buf, err := json2.EncodeClientRequest(args.Method, args.GenesisData)
|
||||
if err != nil {
|
||||
return fmt.Errorf("problem building blockchain genesis state: %w", err)
|
||||
}
|
||||
|
||||
writer := httptest.NewRecorder()
|
||||
service.vm.Ctx.HTTP.Call(
|
||||
/*writer=*/ writer,
|
||||
/*method=*/ "POST",
|
||||
/*base=*/ args.VMID,
|
||||
/*endpoint=*/ args.Endpoint,
|
||||
/*body=*/ bytes.NewBuffer(buf),
|
||||
/*headers=*/ map[string]string{
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
)
|
||||
|
||||
result := CreateGenesisReply{}
|
||||
if err := json2.DecodeClientResponse(writer.Body, &result); err != nil {
|
||||
return fmt.Errorf("problem building blockchain genesis state: %w", err)
|
||||
}
|
||||
genesisBytes = result.Bytes.Bytes
|
||||
} else if args.GenesisData != nil {
|
||||
return errNoMethodWithGenesis
|
||||
// If creating AVM instance, use secp256k1fx
|
||||
// TODO: Document FXs and have user specify them in API call
|
||||
fxIDsSet := ids.Set{}
|
||||
fxIDsSet.Add(fxIDs...)
|
||||
if vmID.Equals(avm.ID) && !fxIDsSet.Contains(secp256k1fx.ID) {
|
||||
fxIDs = append(fxIDs, secp256k1fx.ID)
|
||||
}
|
||||
|
||||
// TODO: Should use the key store to sign this transaction.
|
||||
// TODO: Nonce shouldn't always be 0
|
||||
tx, err := service.vm.newCreateChainTx(0, genesisBytes, vmID, fxIDs, args.Name, service.vm.Ctx.NetworkID, key)
|
||||
if args.SubnetID.Equals(DefaultSubnetID) {
|
||||
return errDSCantValidate
|
||||
}
|
||||
|
||||
tx := CreateChainTx{
|
||||
UnsignedCreateChainTx: UnsignedCreateChainTx{
|
||||
NetworkID: service.vm.Ctx.NetworkID,
|
||||
SubnetID: args.SubnetID,
|
||||
Nonce: uint64(args.PayerNonce),
|
||||
ChainName: args.Name,
|
||||
VMID: vmID,
|
||||
FxIDs: fxIDs,
|
||||
GenesisData: args.GenesisData.Bytes,
|
||||
},
|
||||
PayerAddress: ids.ShortID{},
|
||||
PayerSig: [crypto.SECP256K1RSigLen]byte{},
|
||||
ControlSigs: nil,
|
||||
vm: nil,
|
||||
id: ids.ID{},
|
||||
bytes: nil,
|
||||
}
|
||||
|
||||
txBytes, err := Codec.Marshal(genericTx{Tx: &tx})
|
||||
if err != nil {
|
||||
return fmt.Errorf("problem creating transaction: %w", err)
|
||||
service.vm.Ctx.Log.Error("problem marshaling createChainTx: %v", err)
|
||||
return errCreatingTransaction
|
||||
}
|
||||
|
||||
// Add this tx to the set of unissued txs
|
||||
service.vm.unissuedDecisionTxs = append(service.vm.unissuedDecisionTxs, tx)
|
||||
service.vm.resetTimer()
|
||||
|
||||
reply.BlockchainID = tx.ID()
|
||||
|
||||
response.UnsignedTx.Bytes = txBytes
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -1158,6 +1189,8 @@ type GetBlockchainStatusReply struct {
|
|||
|
||||
// GetBlockchainStatus gets the status of a blockchain with the ID [args.BlockchainID].
|
||||
func (service *Service) GetBlockchainStatus(_ *http.Request, args *GetBlockchainStatusArgs, reply *GetBlockchainStatusReply) error {
|
||||
service.vm.Ctx.Log.Debug("getBlockchainStatus called")
|
||||
|
||||
_, err := service.vm.chainManager.Lookup(args.BlockchainID)
|
||||
if err == nil {
|
||||
reply.Status = Validating
|
||||
|
@ -1212,3 +1245,100 @@ func (service *Service) chainExists(blockID ids.ID, chainID ids.ID) (bool, error
|
|||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// ValidatedByArgs is the arguments for calling ValidatedBy
|
||||
type ValidatedByArgs struct {
|
||||
// ValidatedBy returns the ID of the Subnet validating the blockchain with this ID
|
||||
BlockchainID ids.ID `json:"blockchainID"`
|
||||
}
|
||||
|
||||
// ValidatedByResponse is the reply from calling ValidatedBy
|
||||
type ValidatedByResponse struct {
|
||||
// ID of the Subnet validating the specified blockchain
|
||||
SubnetID ids.ID `json:"subnetID"`
|
||||
}
|
||||
|
||||
// ValidatedBy returns the ID of the Subnet that validates [args.BlockchainID]
|
||||
func (service *Service) ValidatedBy(_ *http.Request, args *ValidatedByArgs, response *ValidatedByResponse) error {
|
||||
service.vm.Ctx.Log.Debug("validatedBy called")
|
||||
|
||||
chain, err := service.vm.getChain(service.vm.DB, args.BlockchainID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
response.SubnetID = chain.SubnetID
|
||||
return nil
|
||||
}
|
||||
|
||||
// ValidatesArgs are the arguments to Validates
|
||||
type ValidatesArgs struct {
|
||||
SubnetID ids.ID `json:"subnetID"`
|
||||
}
|
||||
|
||||
// ValidatesResponse is the response from calling Validates
|
||||
type ValidatesResponse struct {
|
||||
BlockchainIDs []ids.ID `json:"blockchainIDs"`
|
||||
}
|
||||
|
||||
// Validates returns the IDs of the blockchains validated by [args.SubnetID]
|
||||
func (service *Service) Validates(_ *http.Request, args *ValidatesArgs, response *ValidatesResponse) error {
|
||||
service.vm.Ctx.Log.Debug("validates called")
|
||||
|
||||
// Verify that the Subnet exists
|
||||
if _, err := service.vm.getSubnet(service.vm.DB, args.SubnetID); err != nil {
|
||||
return err
|
||||
}
|
||||
// Get the chains that exist
|
||||
chains, err := service.vm.getChains(service.vm.DB)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Filter to get the chains validated by the specified Subnet
|
||||
for _, chain := range chains {
|
||||
if chain.SubnetID.Equals(args.SubnetID) {
|
||||
response.BlockchainIDs = append(response.BlockchainIDs, chain.ID())
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// APIBlockchain is the representation of a blockchain used in API calls
|
||||
type APIBlockchain struct {
|
||||
// Blockchain's ID
|
||||
ID ids.ID `json:"id"`
|
||||
|
||||
// Blockchain's (non-unique) human-readable name
|
||||
Name string `json:"name"`
|
||||
|
||||
// Subnet that validates the blockchain
|
||||
SubnetID ids.ID `json:"subnetID"`
|
||||
|
||||
// Virtual Machine the blockchain runs
|
||||
VMID ids.ID `json:"vmID"`
|
||||
}
|
||||
|
||||
// GetBlockchainsResponse is the response from a call to GetBlockchains
|
||||
type GetBlockchainsResponse struct {
|
||||
// blockchains that exist
|
||||
Blockchains []APIBlockchain `json:"blockchains"`
|
||||
}
|
||||
|
||||
// GetBlockchains returns all of the blockchains that exist
|
||||
func (service *Service) GetBlockchains(_ *http.Request, args *struct{}, response *GetBlockchainsResponse) error {
|
||||
service.vm.Ctx.Log.Debug("getBlockchains called")
|
||||
|
||||
chains, err := service.vm.getChains(service.vm.DB)
|
||||
if err != nil {
|
||||
return fmt.Errorf("couldn't retrieve blockchains: %v", err)
|
||||
}
|
||||
|
||||
for _, chain := range chains {
|
||||
response.Blockchains = append(response.Blockchains, APIBlockchain{
|
||||
ID: chain.ID(),
|
||||
Name: chain.ChainName,
|
||||
SubnetID: chain.SubnetID,
|
||||
VMID: chain.VMID,
|
||||
})
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ func TestAddDefaultSubnetValidator(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestCreateBlockchainArgsParsing(t *testing.T) {
|
||||
jsonString := `{"vmID":"lol","chainName":"awesome","genesisData":{"key":"value"}}`
|
||||
jsonString := `{"vmID":"lol","fxIDs":["secp256k1"], "name":"awesome", "payerNonce":5, "genesisData":"SkB92YpWm4Q2iPnLGCuDPZPgUQMxajqQQuz91oi3xD984f8r"}`
|
||||
args := CreateBlockchainArgs{}
|
||||
err := json.Unmarshal([]byte(jsonString), &args)
|
||||
if err != nil {
|
||||
|
|
|
@ -17,6 +17,7 @@ import (
|
|||
|
||||
var (
|
||||
errEmptyAccountAddress = errors.New("account has empty address")
|
||||
errNoSuchBlockchain = errors.New("there is no blockchain with the specified ID")
|
||||
)
|
||||
|
||||
// TODO: Cache prefixed IDs or use different way of keying into database
|
||||
|
@ -146,7 +147,7 @@ func (vm *VM) putAccount(db database.Database, account Account) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// get the blockchains that exist
|
||||
// get all the blockchains that exist
|
||||
func (vm *VM) getChains(db database.Database) ([]*CreateChainTx, error) {
|
||||
chainsInterface, err := vm.State.Get(db, chainsTypeID, chainsKey)
|
||||
if err != nil {
|
||||
|
@ -154,12 +155,26 @@ func (vm *VM) getChains(db database.Database) ([]*CreateChainTx, error) {
|
|||
}
|
||||
chains, ok := chainsInterface.([]*CreateChainTx)
|
||||
if !ok {
|
||||
vm.Ctx.Log.Warn("expected to retrieve []*CreateChainTx from database but got different type")
|
||||
vm.Ctx.Log.Error("expected to retrieve []*CreateChainTx from database but got different type")
|
||||
return nil, errDBChains
|
||||
}
|
||||
return chains, nil
|
||||
}
|
||||
|
||||
// get a blockchain by its ID
|
||||
func (vm *VM) getChain(db database.Database, ID ids.ID) (*CreateChainTx, error) {
|
||||
chains, err := vm.getChains(db)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, chain := range chains {
|
||||
if chain.ID().Equals(ID) {
|
||||
return chain, nil
|
||||
}
|
||||
}
|
||||
return nil, errNoSuchBlockchain
|
||||
}
|
||||
|
||||
// put the list of blockchains that exist to database
|
||||
func (vm *VM) putChains(db database.Database, chains createChainList) error {
|
||||
if err := vm.State.Put(db, chainsTypeID, chainsKey, chains); err != nil {
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
"net/http"
|
||||
|
||||
"github.com/ava-labs/gecko/ids"
|
||||
"github.com/ava-labs/gecko/utils/crypto"
|
||||
"github.com/ava-labs/gecko/utils/formatting"
|
||||
"github.com/ava-labs/gecko/utils/json"
|
||||
)
|
||||
|
@ -74,11 +75,13 @@ type APIDefaultSubnetValidator struct {
|
|||
// [VMID] is the ID of the VM this chain runs.
|
||||
// [FxIDs] are the IDs of the Fxs the chain supports.
|
||||
// [Name] is a human-readable, non-unique name for the chain.
|
||||
// [SubnetID] is the ID of the subnet that validates the chain
|
||||
type APIChain struct {
|
||||
GenesisData formatting.CB58 `json:"genesisData"`
|
||||
VMID ids.ID `json:"vmID"`
|
||||
FxIDs []ids.ID `json:"fxIDs"`
|
||||
Name string `json:"name"`
|
||||
SubnetID ids.ID `json:"subnetID"`
|
||||
}
|
||||
|
||||
// BuildGenesisArgs are the arguments used to create
|
||||
|
@ -134,8 +137,8 @@ func (*StaticService) BuildGenesis(_ *http.Request, args *BuildGenesisArgs, repl
|
|||
return errAccountHasNoValue
|
||||
}
|
||||
accounts = append(accounts, newAccount(
|
||||
account.Address, // ID
|
||||
0, // nonce
|
||||
account.Address, // ID
|
||||
0, // nonce
|
||||
uint64(account.Balance), // balance
|
||||
))
|
||||
}
|
||||
|
@ -182,12 +185,15 @@ func (*StaticService) BuildGenesis(_ *http.Request, args *BuildGenesisArgs, repl
|
|||
tx := &CreateChainTx{
|
||||
UnsignedCreateChainTx: UnsignedCreateChainTx{
|
||||
NetworkID: uint32(args.NetworkID),
|
||||
SubnetID: chain.SubnetID,
|
||||
Nonce: 0,
|
||||
ChainName: chain.Name,
|
||||
VMID: chain.VMID,
|
||||
FxIDs: chain.FxIDs,
|
||||
GenesisData: chain.GenesisData.Bytes,
|
||||
},
|
||||
ControlSigs: [][crypto.SECP256K1RSigLen]byte{},
|
||||
PayerSig: [crypto.SECP256K1RSigLen]byte{},
|
||||
}
|
||||
if err := tx.initialize(nil); err != nil {
|
||||
return err
|
||||
|
|
|
@ -4,114 +4,12 @@
|
|||
package platformvm
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
"github.com/ava-labs/gecko/ids"
|
||||
"github.com/ava-labs/gecko/utils/formatting"
|
||||
"github.com/ava-labs/gecko/utils/json"
|
||||
)
|
||||
|
||||
func TestBuildGenesis(t *testing.T) {
|
||||
expected := []byte{
|
||||
0x00, 0x00, 0x00, 0x01, 0x01, 0x5c, 0xce, 0x6c,
|
||||
0x55, 0xd6, 0xb5, 0x09, 0x84, 0x5c, 0x8c, 0x4e,
|
||||
0x30, 0xbe, 0xd9, 0x8d, 0x39, 0x1a, 0xe7, 0xf0,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x07, 0x5b, 0xcd, 0x15,
|
||||
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x0b, 0x01, 0x5c, 0xce, 0x6c, 0x55, 0xd6, 0xb5,
|
||||
0x09, 0x84, 0x5c, 0x8c, 0x4e, 0x30, 0xbe, 0xd9,
|
||||
0x8d, 0x39, 0x1a, 0xe7, 0xf0, 0x00, 0x00, 0x00,
|
||||
0x00, 0x3a, 0xde, 0x68, 0xb1, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x01, 0x5c, 0xce, 0x6c, 0x55, 0xd6, 0xb5,
|
||||
0x09, 0x84, 0x5c, 0x8c, 0x4e, 0x30, 0xbe, 0xd9,
|
||||
0x8d, 0x39, 0x1a, 0xe7, 0xf0, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 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, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x13, 0x4d, 0x79, 0x20, 0x46,
|
||||
0x61, 0x76, 0x6f, 0x72, 0x69, 0x74, 0x65, 0x20,
|
||||
0x45, 0x70, 0x69, 0x73, 0x6f, 0x64, 0x65, 0x53,
|
||||
0x6f, 0x75, 0x74, 0x68, 0x20, 0x50, 0x61, 0x72,
|
||||
0x6b, 0x20, 0x65, 0x70, 0x69, 0x73, 0x6f, 0x64,
|
||||
0x65, 0x20, 0x70, 0x6c, 0x61, 0x79, 0x65, 0x72,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x53,
|
||||
0x63, 0x6f, 0x74, 0x74, 0x20, 0x54, 0x65, 0x6e,
|
||||
0x6f, 0x72, 0x6d, 0x61, 0x6e, 0x20, 0x6d, 0x75,
|
||||
0x73, 0x74, 0x20, 0x64, 0x69, 0x65, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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,
|
||||
}
|
||||
|
||||
addr, _ := ids.ShortFromString("8CrVPQZ4VSqgL8zTdvL14G8HqAfrBr4z")
|
||||
genesisData := formatting.CB58{}
|
||||
genesisData.FromString("CGgRrQ3nws7RRMGyDV59cetJBAwmsmDyCSgku")
|
||||
vmID, _ := ids.FromString("dkFD29iYU9e9jah2nrnksTWJUy2VVpg5Lnqd7nQqvCJgR26H4")
|
||||
|
||||
account := APIAccount{
|
||||
Address: addr,
|
||||
Balance: 123456789,
|
||||
}
|
||||
weight := json.Uint64(987654321)
|
||||
validator := APIDefaultSubnetValidator{
|
||||
APIValidator: APIValidator{
|
||||
EndTime: 15,
|
||||
Weight: &weight,
|
||||
ID: addr,
|
||||
},
|
||||
Destination: addr,
|
||||
}
|
||||
chains := APIChain{
|
||||
GenesisData: genesisData,
|
||||
VMID: vmID,
|
||||
Name: "My Favorite Episode",
|
||||
}
|
||||
|
||||
args := BuildGenesisArgs{
|
||||
Accounts: []APIAccount{
|
||||
account,
|
||||
},
|
||||
Validators: []APIDefaultSubnetValidator{
|
||||
validator,
|
||||
},
|
||||
Chains: []APIChain{
|
||||
chains,
|
||||
},
|
||||
Time: 5,
|
||||
}
|
||||
reply := BuildGenesisReply{}
|
||||
|
||||
ss := StaticService{}
|
||||
if err := ss.BuildGenesis(nil, &args, &reply); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !bytes.Equal(reply.Bytes.Bytes, expected) {
|
||||
t.Fatalf("StaticService.BuildGenesis:\nReturned:\n%s\nExpected:\n%s",
|
||||
formatting.DumpBytes{Bytes: reply.Bytes.Bytes},
|
||||
formatting.DumpBytes{Bytes: expected})
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildGenesisInvalidAccountBalance(t *testing.T) {
|
||||
id, _ := ids.ShortFromString("8CrVPQZ4VSqgL8zTdvL14G8HqAfrBr4z")
|
||||
account := APIAccount{
|
||||
|
|
|
@ -151,8 +151,13 @@ func init() {
|
|||
type VM struct {
|
||||
*core.SnowmanVM
|
||||
|
||||
// Node's validator manager
|
||||
// Maps Subnets --> nodes in the Subnet HEAD
|
||||
validators validators.Manager
|
||||
|
||||
// true if the node is being run with staking enabled
|
||||
stakingEnabled bool
|
||||
|
||||
// The node's chain manager
|
||||
chainManager chains.Manager
|
||||
|
||||
|
@ -296,8 +301,8 @@ func (vm *VM) Initialize(
|
|||
})
|
||||
go ctx.Log.RecoverAndPanic(vm.timer.Dispatch)
|
||||
|
||||
if err := vm.updateValidators(DefaultSubnetID); err != nil {
|
||||
ctx.Log.Error("failed to initialize the current validator set: %s", err)
|
||||
if err := vm.initSubnets(); err != nil {
|
||||
ctx.Log.Error("failed to initialize Subnets: %s", err)
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -313,27 +318,67 @@ func (vm *VM) Initialize(
|
|||
return nil
|
||||
}
|
||||
|
||||
// Create all of the chains that the database says should exist
|
||||
// Create all chains that exist that this node validates
|
||||
// Can only be called after initSubnets()
|
||||
func (vm *VM) initBlockchains() error {
|
||||
vm.Ctx.Log.Verbo("platform chain initializing existing blockchains")
|
||||
existingChains, err := vm.getChains(vm.DB)
|
||||
vm.Ctx.Log.Info("initializing blockchains")
|
||||
blockchains, err := vm.getChains(vm.DB) // get blockchains that exist
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, chain := range existingChains { // Create each blockchain
|
||||
chainParams := chains.ChainParameters{
|
||||
ID: chain.ID(),
|
||||
GenesisData: chain.GenesisData,
|
||||
VMAlias: chain.VMID.String(),
|
||||
}
|
||||
for _, fxID := range chain.FxIDs {
|
||||
chainParams.FxAliases = append(chainParams.FxAliases, fxID.String())
|
||||
}
|
||||
vm.chainManager.CreateChain(chainParams)
|
||||
|
||||
for _, chain := range blockchains {
|
||||
vm.createChain(chain)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Set the node's validator manager to be up to date
|
||||
func (vm *VM) initSubnets() error {
|
||||
vm.Ctx.Log.Info("initializing Subnets")
|
||||
subnets, err := vm.getSubnets(vm.DB)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := vm.updateValidators(DefaultSubnetID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, subnet := range subnets {
|
||||
if err := vm.updateValidators(subnet.id); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Create the blockchain described in [tx], but only if this node is a member of
|
||||
// the Subnet that validates the chain
|
||||
func (vm *VM) createChain(tx *CreateChainTx) {
|
||||
// The validators that compose the Subnet that validates this chain
|
||||
validators, subnetExists := vm.validators.GetValidatorSet(tx.SubnetID)
|
||||
if !subnetExists {
|
||||
vm.Ctx.Log.Error("blockchain %s validated by Subnet %s but couldn't get that Subnet. Blockchain not created")
|
||||
return
|
||||
}
|
||||
if !validators.Contains(vm.Ctx.NodeID) && vm.stakingEnabled { // This node doesn't validate this blockchain
|
||||
return
|
||||
}
|
||||
|
||||
chainParams := chains.ChainParameters{
|
||||
ID: tx.ID(),
|
||||
SubnetID: tx.SubnetID,
|
||||
GenesisData: tx.GenesisData,
|
||||
VMAlias: tx.VMID.String(),
|
||||
}
|
||||
for _, fxID := range tx.FxIDs {
|
||||
chainParams.FxAliases = append(chainParams.FxAliases, fxID.String())
|
||||
}
|
||||
vm.chainManager.CreateChain(chainParams)
|
||||
}
|
||||
|
||||
// Shutdown this blockchain
|
||||
func (vm *VM) Shutdown() {
|
||||
vm.timer.Stop()
|
||||
|
@ -663,13 +708,16 @@ func (vm *VM) nextSubnetValidatorChangeTime(db database.Database, subnetID ids.I
|
|||
// Returns:
|
||||
// 1) The validator set of subnet with ID [subnetID] when timestamp is advanced to [timestamp]
|
||||
// 2) The pending validator set of subnet with ID [subnetID] when timestamp is advanced to [timestamp]
|
||||
// 3) The IDs of the validators that start validating [subnetID] between now and [timestamp]
|
||||
// 4) The IDs of the validators that stop validating [subnetID] between now and [timestamp]
|
||||
// Note that this method will not remove validators from the current validator set of the default subnet.
|
||||
// That happens in reward blocks.
|
||||
func (vm *VM) calculateValidators(db database.Database, timestamp time.Time, subnetID ids.ID) (current, pending *EventHeap, err error) {
|
||||
func (vm *VM) calculateValidators(db database.Database, timestamp time.Time, subnetID ids.ID) (current,
|
||||
pending *EventHeap, started, stopped ids.ShortSet, err error) {
|
||||
// remove validators whose end time <= [timestamp]
|
||||
current, err = vm.getCurrentValidators(db, subnetID)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, nil, nil, nil, err
|
||||
}
|
||||
if !subnetID.Equals(DefaultSubnetID) { // validators of default subnet removed in rewardValidatorTxs, not here
|
||||
for current.Len() > 0 {
|
||||
|
@ -678,11 +726,12 @@ func (vm *VM) calculateValidators(db database.Database, timestamp time.Time, sub
|
|||
break
|
||||
}
|
||||
current.Remove()
|
||||
stopped.Add(next.Vdr().ID())
|
||||
}
|
||||
}
|
||||
pending, err = vm.getPendingValidators(db, subnetID)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, nil, nil, nil, err
|
||||
}
|
||||
for pending.Len() > 0 {
|
||||
nextTx := pending.Peek() // pending staker with earliest start time
|
||||
|
@ -691,8 +740,9 @@ func (vm *VM) calculateValidators(db database.Database, timestamp time.Time, sub
|
|||
}
|
||||
heap.Push(current, nextTx)
|
||||
heap.Pop(pending)
|
||||
started.Add(nextTx.Vdr().ID())
|
||||
}
|
||||
return current, pending, nil
|
||||
return current, pending, started, stopped, nil
|
||||
}
|
||||
|
||||
func (vm *VM) getValidators(validatorEvents *EventHeap) []validators.Validator {
|
||||
|
@ -720,10 +770,12 @@ func (vm *VM) getValidators(validatorEvents *EventHeap) []validators.Validator {
|
|||
return vdrList
|
||||
}
|
||||
|
||||
// update the node's validator manager to contain the current validator set of the given Subnet
|
||||
func (vm *VM) updateValidators(subnetID ids.ID) error {
|
||||
validatorSet, ok := vm.validators.GetValidatorSet(subnetID)
|
||||
if !ok {
|
||||
return fmt.Errorf("couldn't get the validator sampler of the %s subnet", subnetID)
|
||||
validatorSet, subnetInitialized := vm.validators.GetValidatorSet(subnetID)
|
||||
if !subnetInitialized { // validator manager doesn't know about this subnet yet
|
||||
validatorSet = validators.NewSet()
|
||||
vm.validators.PutValidatorSet(subnetID, validatorSet)
|
||||
}
|
||||
|
||||
currentValidators, err := vm.getCurrentValidators(vm.DB, subnetID)
|
||||
|
|
|
@ -10,6 +10,7 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/ava-labs/gecko/chains"
|
||||
"github.com/ava-labs/gecko/chains/atomic"
|
||||
"github.com/ava-labs/gecko/database/memdb"
|
||||
"github.com/ava-labs/gecko/ids"
|
||||
|
@ -39,16 +40,17 @@ var (
|
|||
// each key corresponds to an account that has $AVA and a genesis validator
|
||||
keys []*crypto.PrivateKeySECP256K1R
|
||||
|
||||
// amount all genesis validators stake
|
||||
// amount all genesis validators stake in defaultVM
|
||||
defaultStakeAmount uint64
|
||||
|
||||
// balance of accounts that exist at genesis
|
||||
// balance of accounts that exist at genesis in defaultVM
|
||||
defaultBalance = 100 * MinimumStakeAmount
|
||||
|
||||
// At genesis this account has AVA and is validating the default subnet
|
||||
defaultKey *crypto.PrivateKeySECP256K1R
|
||||
|
||||
// non-default subnet that exists at genesis in defaultVM
|
||||
// non-default Subnet that exists at genesis in defaultVM
|
||||
// Its controlKeys are keys[0], keys[1], keys[2]
|
||||
testSubnet1 *CreateSubnetTx
|
||||
testSubnet1ControlKeys []*crypto.PrivateKeySECP256K1R
|
||||
)
|
||||
|
@ -116,7 +118,8 @@ func defaultVM() *VM {
|
|||
}
|
||||
|
||||
vm := &VM{
|
||||
SnowmanVM: &core.SnowmanVM{},
|
||||
SnowmanVM: &core.SnowmanVM{},
|
||||
chainManager: chains.MockManager{},
|
||||
}
|
||||
|
||||
defaultSubnet := validators.NewSet()
|
||||
|
@ -136,7 +139,7 @@ func defaultVM() *VM {
|
|||
testNetworkID,
|
||||
0,
|
||||
[]ids.ShortID{keys[0].PublicKey().Address(), keys[1].PublicKey().Address(), keys[2].PublicKey().Address()}, // control keys are keys[0], keys[1], keys[2]
|
||||
2, // 2 sigs from keys[0], keys[1], keys[2] needed to add validator to this subnet
|
||||
2, // threshold; 2 sigs from keys[0], keys[1], keys[2] needed to add validator to this subnet
|
||||
keys[0],
|
||||
)
|
||||
if err != nil {
|
||||
|
@ -765,11 +768,13 @@ func TestCreateChain(t *testing.T) {
|
|||
|
||||
tx, err := vm.newCreateChainTx(
|
||||
defaultNonce+1,
|
||||
testSubnet1.id,
|
||||
nil,
|
||||
timestampvm.ID,
|
||||
nil,
|
||||
"name ",
|
||||
"name",
|
||||
testNetworkID,
|
||||
[]*crypto.PrivateKeySECP256K1R{testSubnet1ControlKeys[0], testSubnet1ControlKeys[1]},
|
||||
keys[0],
|
||||
)
|
||||
if err != nil {
|
||||
|
@ -806,7 +811,7 @@ func TestCreateChain(t *testing.T) {
|
|||
}
|
||||
|
||||
// Verify tx fee was deducted
|
||||
account, err := vm.getAccount(vm.DB, tx.Key().Address())
|
||||
account, err := vm.getAccount(vm.DB, tx.PayerAddress)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
|
|
@ -74,10 +74,6 @@ func init() {
|
|||
networkID, err := genesis.NetworkID(*networkName)
|
||||
errs.Add(err)
|
||||
|
||||
if networkID != genesis.LocalID {
|
||||
errs.Add(fmt.Errorf("the only supported networkID is: %s", genesis.LocalName))
|
||||
}
|
||||
|
||||
config.NetworkID = networkID
|
||||
|
||||
// Remote:
|
||||
|
|
Loading…
Reference in New Issue