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
|
// That is, [chainID].String() is an alias for the chain, too
|
||||||
ids.Aliaser
|
ids.Aliaser
|
||||||
|
|
||||||
|
stakingEnabled bool // True iff the network has staking enabled
|
||||||
log logging.Logger
|
log logging.Logger
|
||||||
logFactory logging.Factory
|
logFactory logging.Factory
|
||||||
vmManager vms.Manager // Manage mappings from vm ID --> vm
|
vmManager vms.Manager // Manage mappings from vm ID --> vm
|
||||||
|
@ -122,6 +123,7 @@ type manager struct {
|
||||||
// <validators> validate this chain
|
// <validators> validate this chain
|
||||||
// TODO: Make this function take less arguments
|
// TODO: Make this function take less arguments
|
||||||
func New(
|
func New(
|
||||||
|
stakingEnabled bool,
|
||||||
log logging.Logger,
|
log logging.Logger,
|
||||||
logFactory logging.Factory,
|
logFactory logging.Factory,
|
||||||
vmManager vms.Manager,
|
vmManager vms.Manager,
|
||||||
|
@ -146,6 +148,7 @@ func New(
|
||||||
router.Initialize(log, &timeoutManager)
|
router.Initialize(log, &timeoutManager)
|
||||||
|
|
||||||
m := &manager{
|
m := &manager{
|
||||||
|
stakingEnabled: stakingEnabled,
|
||||||
log: log,
|
log: log,
|
||||||
logFactory: logFactory,
|
logFactory: logFactory,
|
||||||
vmManager: vmManager,
|
vmManager: vmManager,
|
||||||
|
@ -261,7 +264,13 @@ func (m *manager) ForceCreateChain(chain ChainParameters) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// The validators of this blockchain
|
// 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 {
|
if !ok {
|
||||||
m.log.Error("couldn't get validator set of subnet with ID %s. The subnet may not exist", chain.SubnetID)
|
m.log.Error("couldn't get validator set of subnet with ID %s. The subnet may not exist", chain.SubnetID)
|
||||||
return
|
return
|
||||||
|
@ -358,7 +367,7 @@ func (m *manager) createAvalancheChain(
|
||||||
msgChan := make(chan common.Message, defaultChannelSize)
|
msgChan := make(chan common.Message, defaultChannelSize)
|
||||||
|
|
||||||
if err := vm.Initialize(ctx, vmDB, genesisData, msgChan, fxs); err != nil {
|
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
|
// 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
|
package genesis
|
||||||
|
|
||||||
// TODO: Move this to a separate repo and leave only a byte array
|
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
|
"math/big"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"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/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/avm"
|
||||||
"github.com/ava-labs/gecko/vms/components/codec"
|
"github.com/ava-labs/gecko/vms/components/codec"
|
||||||
"github.com/ava-labs/gecko/vms/evm"
|
"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"},
|
spdagvm.ID.Key(): []string{"spdag"},
|
||||||
spchainvm.ID.Key(): []string{"spchain"},
|
spchainvm.ID.Key(): []string{"spchain"},
|
||||||
timestampvm.ID.Key(): []string{"timestamp"},
|
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
|
genesis := &platformvm.Genesis{} // TODO let's not re-create genesis to do aliasing
|
||||||
platformvm.Codec.Unmarshal(genesisBytes, genesis) // TODO check for error
|
platformvm.Codec.Unmarshal(genesisBytes, genesis) // TODO check for error
|
||||||
genesis.Initialize()
|
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
|
// Since the Platform Chain causes the creation of all other
|
||||||
// chains, this function returns the genesis data of the entire network.
|
// chains, this function returns the genesis data of the entire network.
|
||||||
// The ID of the new network is [networkID].
|
// The ID of the new network is [networkID].
|
||||||
func Genesis(networkID uint32) []byte {
|
func Genesis(networkID uint32) ([]byte, error) {
|
||||||
if networkID != LocalID {
|
// Specify the genesis state of the AVM
|
||||||
panic("unknown network ID provided")
|
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{
|
// Specify the genesis state of Athereum (the built-in instance of the EVM)
|
||||||
0x00, 0x00, 0x00, 0x01, 0x3c, 0xb7, 0xd3, 0x84,
|
evmBalance, success := new(big.Int).SetString("33b2e3c9fd0804000000000", 16)
|
||||||
0x2e, 0x8c, 0xee, 0x6a, 0x0e, 0xbd, 0x09, 0xf1,
|
if success != true {
|
||||||
0xfe, 0x88, 0x4f, 0x68, 0x61, 0xe1, 0xb2, 0x9c,
|
return nil, errors.New("problem creating evm genesis state")
|
||||||
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,
|
|
||||||
}
|
}
|
||||||
|
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 ...
|
// VMGenesis ...
|
||||||
func VMGenesis(networkID uint32, vmID ids.ID) *platformvm.CreateChainTx {
|
func VMGenesis(networkID uint32, vmID ids.ID) *platformvm.CreateChainTx {
|
||||||
genesisBytes := Genesis(networkID)
|
genesisBytes, _ := Genesis(networkID)
|
||||||
genesis := platformvm.Genesis{}
|
genesis := platformvm.Genesis{}
|
||||||
platformvm.Codec.Unmarshal(genesisBytes, &genesis)
|
platformvm.Codec.Unmarshal(genesisBytes, &genesis)
|
||||||
if err := genesis.Initialize(); err != nil {
|
if err := genesis.Initialize(); err != nil {
|
||||||
|
|
|
@ -106,7 +106,7 @@ func TestAliases(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGenesis(t *testing.T) {
|
func TestGenesis(t *testing.T) {
|
||||||
genesisBytes := Genesis(LocalID)
|
genesisBytes, _ := Genesis(LocalID)
|
||||||
genesis := platformvm.Genesis{}
|
genesis := platformvm.Genesis{}
|
||||||
if err := platformvm.Codec.Unmarshal(genesisBytes, &genesis); err != nil {
|
if err := platformvm.Codec.Unmarshal(genesisBytes, &genesis); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
|
|
|
@ -120,10 +120,6 @@ func init() {
|
||||||
networkID, err := genesis.NetworkID(*networkName)
|
networkID, err := genesis.NetworkID(*networkName)
|
||||||
errs.Add(err)
|
errs.Add(err)
|
||||||
|
|
||||||
if networkID != genesis.LocalID {
|
|
||||||
errs.Add(fmt.Errorf("the only supported networkID is: %s", genesis.LocalName))
|
|
||||||
}
|
|
||||||
|
|
||||||
Config.NetworkID = networkID
|
Config.NetworkID = networkID
|
||||||
|
|
||||||
// DB:
|
// DB:
|
||||||
|
|
18
node/node.go
18
node/node.go
|
@ -354,8 +354,13 @@ func (n *Node) initChains() {
|
||||||
n.Log.Info("initializing chains")
|
n.Log.Info("initializing chains")
|
||||||
|
|
||||||
vdrs := n.vdrs
|
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 {
|
if !n.Config.EnableStaking {
|
||||||
defaultSubnetValidators := validators.NewSet()
|
defaultSubnetValidators := validators.NewSet()
|
||||||
|
defaultSubnetValidators.Add(validators.NewValidator(n.ID, 1))
|
||||||
vdrs = validators.NewManager()
|
vdrs = validators.NewManager()
|
||||||
vdrs.PutValidatorSet(platformvm.DefaultSubnetID, defaultSubnetValidators)
|
vdrs.PutValidatorSet(platformvm.DefaultSubnetID, defaultSubnetValidators)
|
||||||
}
|
}
|
||||||
|
@ -363,10 +368,11 @@ func (n *Node) initChains() {
|
||||||
n.vmManager.RegisterVMFactory(
|
n.vmManager.RegisterVMFactory(
|
||||||
/*vmID=*/ platformvm.ID,
|
/*vmID=*/ platformvm.ID,
|
||||||
/*vmFactory=*/ &platformvm.Factory{
|
/*vmFactory=*/ &platformvm.Factory{
|
||||||
ChainManager: n.chainManager,
|
ChainManager: n.chainManager,
|
||||||
Validators: vdrs,
|
Validators: vdrs,
|
||||||
AVA: genesis.AVAAssetID(n.Config.NetworkID),
|
StakingEnabled: n.Config.EnableStaking,
|
||||||
AVM: genesis.VMGenesis(n.Config.NetworkID, avm.ID).ID(),
|
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))
|
beacons.Add(validators.NewValidator(peer.ID, 1))
|
||||||
}
|
}
|
||||||
|
|
||||||
genesisBytes := genesis.Genesis(n.Config.NetworkID)
|
genesisBytes, _ := genesis.Genesis(n.Config.NetworkID)
|
||||||
|
|
||||||
// Create the Platform Chain
|
// Create the Platform Chain
|
||||||
n.chainManager.ForceCreateChain(chains.ChainParameters{
|
n.chainManager.ForceCreateChain(chains.ChainParameters{
|
||||||
ID: ids.Empty,
|
ID: ids.Empty,
|
||||||
|
SubnetID: platformvm.DefaultSubnetID,
|
||||||
GenesisData: genesisBytes, // Specifies other chains to create
|
GenesisData: genesisBytes, // Specifies other chains to create
|
||||||
VMAlias: platformvm.ID.String(),
|
VMAlias: platformvm.ID.String(),
|
||||||
CustomBeacons: beacons,
|
CustomBeacons: beacons,
|
||||||
|
@ -409,6 +416,7 @@ func (n *Node) initAPIServer() {
|
||||||
// Assumes n.DB, n.vdrs all initialized (non-nil)
|
// Assumes n.DB, n.vdrs all initialized (non-nil)
|
||||||
func (n *Node) initChainManager() {
|
func (n *Node) initChainManager() {
|
||||||
n.chainManager = chains.New(
|
n.chainManager = chains.New(
|
||||||
|
n.Config.EnableStaking,
|
||||||
n.Log,
|
n.Log,
|
||||||
n.LogFactory,
|
n.LogFactory,
|
||||||
n.vmManager,
|
n.vmManager,
|
||||||
|
|
|
@ -7,6 +7,8 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/ava-labs/gecko/ids"
|
||||||
|
|
||||||
"github.com/ava-labs/gecko/database"
|
"github.com/ava-labs/gecko/database"
|
||||||
"github.com/ava-labs/gecko/database/versiondb"
|
"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
|
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 {
|
if err != nil {
|
||||||
return nil, nil, nil, nil, err
|
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
|
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
|
// 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)
|
subnets, err := tx.vm.getSubnets(db)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, nil, nil, err
|
return nil, nil, nil, nil, err
|
||||||
}
|
}
|
||||||
for _, subnet := range subnets {
|
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 {
|
if err != nil {
|
||||||
return nil, nil, nil, nil, err
|
return nil, nil, nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := tx.vm.putCurrentValidators(onCommitDB, current, subnet.id); err != nil {
|
if err := tx.vm.putCurrentValidators(onCommitDB, current, subnet.id); err != nil {
|
||||||
return nil, nil, nil, nil, err
|
return nil, nil, nil, nil, err
|
||||||
}
|
}
|
||||||
if err := tx.vm.putPendingValidators(onCommitDB, pending, subnet.id); err != nil {
|
if err := tx.vm.putPendingValidators(onCommitDB, pending, subnet.id); err != nil {
|
||||||
return nil, nil, nil, nil, err
|
return nil, nil, nil, nil, err
|
||||||
}
|
}
|
||||||
|
startedValidating[subnet.ID()] = started
|
||||||
}
|
}
|
||||||
|
|
||||||
// If this block is committed, update the validator sets
|
// If this block is committed, update the validator sets
|
||||||
// onAbortDB or onCommitDB should commit (flush to vm.DB) before this is called
|
// 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)
|
subnets, err := tx.vm.getSubnets(tx.vm.DB)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tx.vm.Ctx.Log.Error("failed to get subnets: %s", err)
|
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 {
|
for _, subnet := range subnets {
|
||||||
if err := tx.vm.updateValidators(subnet.id); err != nil {
|
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 {
|
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
|
// Specify what the state of the chain will be if this proposal is aborted
|
||||||
onAbortDB := versiondb.New(db) // state doesn't change
|
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
|
// InitiallyPrefersCommit returns true if the proposed time isn't after the
|
||||||
|
|
|
@ -7,7 +7,6 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/ava-labs/gecko/chains"
|
|
||||||
"github.com/ava-labs/gecko/database"
|
"github.com/ava-labs/gecko/database"
|
||||||
"github.com/ava-labs/gecko/ids"
|
"github.com/ava-labs/gecko/ids"
|
||||||
"github.com/ava-labs/gecko/utils/crypto"
|
"github.com/ava-labs/gecko/utils/crypto"
|
||||||
|
@ -15,8 +14,9 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
errInvalidVMID = errors.New("invalid VM ID")
|
errInvalidVMID = errors.New("invalid VM ID")
|
||||||
errFxIDsNotSortedAndUnique = errors.New("feature extensions IDs must be sorted and unique")
|
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
|
// UnsignedCreateChainTx is an unsigned CreateChainTx
|
||||||
|
@ -24,6 +24,9 @@ type UnsignedCreateChainTx struct {
|
||||||
// ID of the network this blockchain exists on
|
// ID of the network this blockchain exists on
|
||||||
NetworkID uint32 `serialize:"true"`
|
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.
|
// Next unused nonce of account paying the transaction fee for this transaction.
|
||||||
// Currently unused, as there are no tx fees.
|
// Currently unused, as there are no tx fees.
|
||||||
Nonce uint64 `serialize:"true"`
|
Nonce uint64 `serialize:"true"`
|
||||||
|
@ -37,7 +40,7 @@ type UnsignedCreateChainTx struct {
|
||||||
// IDs of the feature extensions running on the new chain
|
// IDs of the feature extensions running on the new chain
|
||||||
FxIDs []ids.ID `serialize:"true"`
|
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"`
|
GenesisData []byte `serialize:"true"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,11 +48,19 @@ type UnsignedCreateChainTx struct {
|
||||||
type CreateChainTx struct {
|
type CreateChainTx struct {
|
||||||
UnsignedCreateChainTx `serialize:"true"`
|
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
|
vm *VM
|
||||||
id ids.ID
|
id ids.ID
|
||||||
key crypto.PublicKey // public key of transaction signer
|
|
||||||
bytes []byte
|
bytes []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,10 +75,6 @@ func (tx *CreateChainTx) initialize(vm *VM) error {
|
||||||
// ID of this transaction
|
// ID of this transaction
|
||||||
func (tx *CreateChainTx) ID() ids.ID { return tx.id }
|
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
|
// Bytes returns the byte representation of a CreateChainTx
|
||||||
func (tx *CreateChainTx) Bytes() []byte { return tx.bytes }
|
func (tx *CreateChainTx) Bytes() []byte { return tx.bytes }
|
||||||
|
|
||||||
|
@ -77,8 +84,8 @@ func (tx *CreateChainTx) SyntacticVerify() error {
|
||||||
switch {
|
switch {
|
||||||
case tx == nil:
|
case tx == nil:
|
||||||
return errNilTx
|
return errNilTx
|
||||||
case tx.key != nil:
|
case !tx.PayerAddress.IsZero(): // Only verify the transaction once
|
||||||
return nil // Only verify the transaction once
|
return nil
|
||||||
case tx.NetworkID != tx.vm.Ctx.NetworkID: // verify the transaction is on this network
|
case tx.NetworkID != tx.vm.Ctx.NetworkID: // verify the transaction is on this network
|
||||||
return errWrongNetworkID
|
return errWrongNetworkID
|
||||||
case tx.id.IsZero():
|
case tx.id.IsZero():
|
||||||
|
@ -87,6 +94,8 @@ func (tx *CreateChainTx) SyntacticVerify() error {
|
||||||
return errInvalidVMID
|
return errInvalidVMID
|
||||||
case !ids.IsSortedAndUniqueIDs(tx.FxIDs):
|
case !ids.IsSortedAndUniqueIDs(tx.FxIDs):
|
||||||
return errFxIDsNotSortedAndUnique
|
return errFxIDsNotSortedAndUnique
|
||||||
|
case !crypto.IsSortedAndUniqueSECP2561RSigs(tx.ControlSigs):
|
||||||
|
return errControlSigsNotSortedAndUnique
|
||||||
}
|
}
|
||||||
|
|
||||||
unsignedIntf := interface{}(&tx.UnsignedCreateChainTx)
|
unsignedIntf := interface{}(&tx.UnsignedCreateChainTx)
|
||||||
|
@ -95,11 +104,11 @@ func (tx *CreateChainTx) SyntacticVerify() error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
key, err := tx.vm.factory.RecoverPublicKey(unsignedBytes, tx.Sig[:])
|
payerKey, err := tx.vm.factory.RecoverPublicKey(unsignedBytes, tx.PayerSig[:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
tx.key = key
|
tx.PayerAddress = payerKey.Address()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -125,10 +134,12 @@ func (tx *CreateChainTx) SemanticVerify(db database.Database) (func(), error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deduct tx fee from payer's account
|
// 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 {
|
if err != nil {
|
||||||
return nil, err
|
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)
|
account, err = account.Remove(0, tx.Nonce)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -137,20 +148,55 @@ func (tx *CreateChainTx) SemanticVerify(db database.Database) (func(), error) {
|
||||||
return nil, err
|
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() {
|
onAccept := func() {
|
||||||
chainParams := chains.ChainParameters{
|
tx.vm.createChain(tx)
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return onAccept, nil
|
return onAccept, nil
|
||||||
|
@ -166,10 +212,14 @@ func (chains createChainList) Bytes() []byte {
|
||||||
return bytes
|
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{
|
tx := &CreateChainTx{
|
||||||
UnsignedCreateChainTx: UnsignedCreateChainTx{
|
UnsignedCreateChainTx: UnsignedCreateChainTx{
|
||||||
NetworkID: networkID,
|
NetworkID: networkID,
|
||||||
|
SubnetID: subnetID,
|
||||||
Nonce: nonce,
|
Nonce: nonce,
|
||||||
GenesisData: genesisData,
|
GenesisData: genesisData,
|
||||||
VMID: vmID,
|
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)
|
unsignedIntf := interface{}(&tx.UnsignedCreateChainTx)
|
||||||
unsignedBytes, err := Codec.Marshal(&unsignedIntf) // Byte repr. of unsigned transaction
|
unsignedBytes, err := Codec.Marshal(&unsignedIntf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
copy(tx.Sig[:], sig)
|
copy(tx.PayerSig[:], payerSig)
|
||||||
|
|
||||||
return tx, tx.initialize(vm)
|
return tx, tx.initialize(vm)
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,8 +6,8 @@ package platformvm
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/ava-labs/gecko/database/versiondb"
|
|
||||||
"github.com/ava-labs/gecko/ids"
|
"github.com/ava-labs/gecko/ids"
|
||||||
|
"github.com/ava-labs/gecko/utils/crypto"
|
||||||
"github.com/ava-labs/gecko/vms/avm"
|
"github.com/ava-labs/gecko/vms/avm"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -24,18 +24,19 @@ func TestCreateChainTxSyntacticVerify(t *testing.T) {
|
||||||
// Case 2: network ID is wrong
|
// Case 2: network ID is wrong
|
||||||
tx, err := vm.newCreateChainTx(
|
tx, err := vm.newCreateChainTx(
|
||||||
defaultNonce+1,
|
defaultNonce+1,
|
||||||
|
testSubnet1.id,
|
||||||
nil,
|
nil,
|
||||||
avm.ID,
|
avm.ID,
|
||||||
nil,
|
nil,
|
||||||
"chain name",
|
"chain name",
|
||||||
testNetworkID+1,
|
testNetworkID+1,
|
||||||
|
[]*crypto.PrivateKeySECP256K1R{testSubnet1ControlKeys[0], testSubnet1ControlKeys[1]},
|
||||||
defaultKey,
|
defaultKey,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
err = tx.SyntacticVerify()
|
err = tx.SyntacticVerify()
|
||||||
t.Log(err)
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatal("should've errored because network ID is wrong")
|
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
|
// case 3: tx ID is empty
|
||||||
tx, err = vm.newCreateChainTx(
|
tx, err = vm.newCreateChainTx(
|
||||||
defaultNonce+1,
|
defaultNonce+1,
|
||||||
|
testSubnet1.id,
|
||||||
nil,
|
nil,
|
||||||
avm.ID,
|
avm.ID,
|
||||||
nil,
|
nil,
|
||||||
"chain name",
|
"chain name",
|
||||||
testNetworkID,
|
testNetworkID,
|
||||||
|
[]*crypto.PrivateKeySECP256K1R{testSubnet1ControlKeys[0], testSubnet1ControlKeys[1]},
|
||||||
defaultKey,
|
defaultKey,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -61,11 +64,13 @@ func TestCreateChainTxSyntacticVerify(t *testing.T) {
|
||||||
// Case 4: vm ID is empty
|
// Case 4: vm ID is empty
|
||||||
tx, err = vm.newCreateChainTx(
|
tx, err = vm.newCreateChainTx(
|
||||||
defaultNonce+1,
|
defaultNonce+1,
|
||||||
|
testSubnet1.id,
|
||||||
nil,
|
nil,
|
||||||
avm.ID,
|
avm.ID,
|
||||||
nil,
|
nil,
|
||||||
"chain name",
|
"chain name",
|
||||||
testNetworkID,
|
testNetworkID,
|
||||||
|
[]*crypto.PrivateKeySECP256K1R{testSubnet1ControlKeys[0], testSubnet1ControlKeys[1]},
|
||||||
defaultKey,
|
defaultKey,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -75,62 +80,189 @@ func TestCreateChainTxSyntacticVerify(t *testing.T) {
|
||||||
if err := tx.SyntacticVerify(); err == nil {
|
if err := tx.SyntacticVerify(); err == nil {
|
||||||
t.Fatal("should've errored because tx ID is empty")
|
t.Fatal("should've errored because tx ID is empty")
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
func TestSemanticVerify(t *testing.T) {
|
// Case 5: Control sigs not sorted
|
||||||
vm := defaultVM()
|
tx, err = vm.newCreateChainTx(
|
||||||
|
|
||||||
// create a tx
|
|
||||||
tx, err := vm.newCreateChainTx(
|
|
||||||
defaultNonce+1,
|
defaultNonce+1,
|
||||||
|
testSubnet1.id,
|
||||||
nil,
|
nil,
|
||||||
avm.ID,
|
avm.ID,
|
||||||
nil,
|
nil,
|
||||||
"chain name",
|
"chain name",
|
||||||
testNetworkID,
|
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,
|
defaultKey,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
newDB := versiondb.New(vm.DB)
|
_, err = tx.SemanticVerify(vm.DB)
|
||||||
|
if err == nil {
|
||||||
_, err = tx.SemanticVerify(newDB)
|
t.Fatal("should have errored because there are no control sigs")
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
chains, err := vm.getChains(newDB)
|
// Case 2: 1 control sig (2 are needed)
|
||||||
if err != nil {
|
tx, err = vm.newCreateChainTx(
|
||||||
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(
|
|
||||||
defaultNonce+1,
|
defaultNonce+1,
|
||||||
|
testSubnet1.id,
|
||||||
nil,
|
nil,
|
||||||
avm.ID,
|
avm.ID,
|
||||||
nil,
|
nil,
|
||||||
"chain name",
|
"chain name",
|
||||||
testNetworkID,
|
testNetworkID,
|
||||||
|
[]*crypto.PrivateKeySECP256K1R{testSubnet1ControlKeys[0]},
|
||||||
defaultKey,
|
defaultKey,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
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 {
|
if err := vm.putChains(vm.DB, []*CreateChainTx{tx}); err != nil {
|
||||||
t.Fatal(err)
|
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)
|
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"
|
"fmt"
|
||||||
|
|
||||||
"github.com/ava-labs/gecko/database"
|
"github.com/ava-labs/gecko/database"
|
||||||
|
|
||||||
"github.com/ava-labs/gecko/ids"
|
"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/crypto"
|
||||||
"github.com/ava-labs/gecko/utils/hashing"
|
"github.com/ava-labs/gecko/utils/hashing"
|
||||||
)
|
)
|
||||||
|
@ -17,8 +17,10 @@ import (
|
||||||
const maxThreshold = 25
|
const maxThreshold = 25
|
||||||
|
|
||||||
var (
|
var (
|
||||||
errThresholdExceedsKeysLen = errors.New("threshold must be no more than number of control keys")
|
errThresholdExceedsKeysLen = errors.New("threshold must be no more than number of control keys")
|
||||||
errThresholdTooHigh = fmt.Errorf("threshold can't be greater than %d", maxThreshold)
|
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
|
// UnsignedCreateSubnetTx is an unsigned proposal to create a new subnet
|
||||||
|
@ -41,11 +43,8 @@ type UnsignedCreateSubnetTx struct {
|
||||||
type CreateSubnetTx struct {
|
type CreateSubnetTx struct {
|
||||||
UnsignedCreateSubnetTx `serialize:"true"`
|
UnsignedCreateSubnetTx `serialize:"true"`
|
||||||
|
|
||||||
// The VM this tx exists within
|
// Signature on the UnsignedCreateSubnetTx's byte repr
|
||||||
vm *VM
|
Sig [crypto.SECP256K1RSigLen]byte `serialize:"true"`
|
||||||
|
|
||||||
// ID is this transaction's ID
|
|
||||||
id ids.ID
|
|
||||||
|
|
||||||
// The public key that signed this transaction
|
// The public key that signed this transaction
|
||||||
// The transaction fee will be paid from the corresponding account
|
// 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] is non-nil iff this tx is valid
|
||||||
key crypto.PublicKey
|
key crypto.PublicKey
|
||||||
|
|
||||||
// Signature on the UnsignedCreateSubnetTx's byte repr
|
// The VM this tx exists within
|
||||||
Sig [crypto.SECP256K1RSigLen]byte `serialize:"true"`
|
vm *VM
|
||||||
|
|
||||||
|
// ID is this transaction's ID
|
||||||
|
id ids.ID
|
||||||
|
|
||||||
// Byte representation of this transaction (including signature)
|
// Byte representation of this transaction (including signature)
|
||||||
bytes []byte
|
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 }
|
func (tx *CreateSubnetTx) ID() ids.ID { return tx.id }
|
||||||
|
|
||||||
// SyntacticVerify nil iff [tx] is syntactically valid.
|
// SyntacticVerify nil iff [tx] is syntactically valid.
|
||||||
|
@ -77,6 +79,12 @@ func (tx *CreateSubnetTx) SyntacticVerify() error {
|
||||||
return errWrongNetworkID
|
return errWrongNetworkID
|
||||||
case tx.Threshold > uint16(len(tx.ControlKeys)):
|
case tx.Threshold > uint16(len(tx.ControlKeys)):
|
||||||
return errThresholdExceedsKeysLen
|
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
|
// Byte representation of the unsigned transaction
|
||||||
|
@ -107,12 +115,6 @@ func (tx *CreateSubnetTx) SemanticVerify(db database.Database) (func(), error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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
|
subnets = append(subnets, tx) // add new subnet
|
||||||
if err := tx.vm.putSubnets(db, subnets); err != nil {
|
if err := tx.vm.putSubnets(db, subnets); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -131,7 +133,12 @@ func (tx *CreateSubnetTx) SemanticVerify(db database.Database) (func(), error) {
|
||||||
return nil, err
|
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]
|
// Bytes returns the byte representation of [tx]
|
||||||
|
@ -159,10 +166,11 @@ func (tx *CreateSubnetTx) initialize(vm *VM) error {
|
||||||
return nil
|
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,
|
func (vm *VM) newCreateSubnetTx(networkID uint32, nonce uint64, controlKeys []ids.ShortID,
|
||||||
threshold uint16, payerKey *crypto.PrivateKeySECP256K1R,
|
threshold uint16, payerKey *crypto.PrivateKeySECP256K1R,
|
||||||
) (*CreateSubnetTx, error) {
|
) (*CreateSubnetTx, error) {
|
||||||
|
|
||||||
tx := &CreateSubnetTx{UnsignedCreateSubnetTx: UnsignedCreateSubnetTx{
|
tx := &CreateSubnetTx{UnsignedCreateSubnetTx: UnsignedCreateSubnetTx{
|
||||||
NetworkID: networkID,
|
NetworkID: networkID,
|
||||||
Nonce: nonce,
|
Nonce: nonce,
|
||||||
|
@ -170,6 +178,17 @@ func (vm *VM) newCreateSubnetTx(networkID uint32, nonce uint64, controlKeys []id
|
||||||
Threshold: threshold,
|
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)
|
unsignedIntf := interface{}(&tx.UnsignedCreateSubnetTx)
|
||||||
unsignedBytes, err := Codec.Marshal(&unsignedIntf)
|
unsignedBytes, err := Codec.Marshal(&unsignedIntf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -183,7 +183,7 @@ func (vm *VM) newExportTx(nonce uint64, networkID uint32, outs []*ava.Transferab
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
sig, err := key.Sign(unsignedBytes)
|
sig, err := from.Sign(unsignedBytes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,18 +16,20 @@ var (
|
||||||
|
|
||||||
// Factory can create new instances of the Platform Chain
|
// Factory can create new instances of the Platform Chain
|
||||||
type Factory struct {
|
type Factory struct {
|
||||||
ChainManager chains.Manager
|
ChainManager chains.Manager
|
||||||
Validators validators.Manager
|
Validators validators.Manager
|
||||||
AVA ids.ID
|
StakingEnabled bool
|
||||||
AVM ids.ID
|
AVA ids.ID
|
||||||
|
AVM ids.ID
|
||||||
}
|
}
|
||||||
|
|
||||||
// New returns a new instance of the Platform Chain
|
// New returns a new instance of the Platform Chain
|
||||||
func (f *Factory) New() interface{} {
|
func (f *Factory) New() interface{} {
|
||||||
return &VM{
|
return &VM{
|
||||||
chainManager: f.ChainManager,
|
chainManager: f.ChainManager,
|
||||||
validators: f.Validators,
|
validators: f.Validators,
|
||||||
ava: f.AVA,
|
stakingEnabled: f.StakingEnabled,
|
||||||
avm: f.AVM,
|
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{
|
tx := &ImportTx{UnsignedImportTx: UnsignedImportTx{
|
||||||
NetworkID: networkID,
|
NetworkID: networkID,
|
||||||
Nonce: nonce,
|
Nonce: nonce,
|
||||||
Account: key.PublicKey().Address(),
|
Account: to.PublicKey().Address(),
|
||||||
Ins: ins,
|
Ins: ins,
|
||||||
}}
|
}}
|
||||||
|
|
||||||
|
@ -258,7 +258,7 @@ func (vm *VM) newImportTx(nonce uint64, networkID uint32, ins []*ava.Transferabl
|
||||||
tx.Creds = append(tx.Creds, cred)
|
tx.Creds = append(tx.Creds, cred)
|
||||||
}
|
}
|
||||||
|
|
||||||
sig, err := key.SignHash(hash)
|
sig, err := to.SignHash(hash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,9 +8,6 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
|
||||||
|
|
||||||
"github.com/gorilla/rpc/v2/json2"
|
|
||||||
|
|
||||||
"github.com/ava-labs/gecko/database"
|
"github.com/ava-labs/gecko/database"
|
||||||
"github.com/ava-labs/gecko/ids"
|
"github.com/ava-labs/gecko/ids"
|
||||||
|
@ -19,39 +16,26 @@ import (
|
||||||
"github.com/ava-labs/gecko/utils/hashing"
|
"github.com/ava-labs/gecko/utils/hashing"
|
||||||
"github.com/ava-labs/gecko/utils/json"
|
"github.com/ava-labs/gecko/utils/json"
|
||||||
"github.com/ava-labs/gecko/utils/math"
|
"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/components/ava"
|
||||||
"github.com/ava-labs/gecko/vms/secp256k1fx"
|
"github.com/ava-labs/gecko/vms/secp256k1fx"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
errMissingDecisionBlock = errors.New("should have a decision block within the past two blocks")
|
errMissingDecisionBlock = errors.New("should have a decision block within the past two blocks")
|
||||||
errParsingID = errors.New("error parsing ID")
|
errParsingID = errors.New("error parsing ID")
|
||||||
errGetAccount = errors.New("error retrieving account information")
|
errGetAccount = errors.New("error retrieving account information")
|
||||||
errGetAccounts = errors.New("error getting accounts controlled by specified user")
|
errGetAccounts = errors.New("error getting accounts controlled by specified user")
|
||||||
errGetUser = errors.New("error while getting user. Does user exist?")
|
errGetUser = errors.New("error while getting user. Does user exist?")
|
||||||
errNoMethodWithGenesis = errors.New("no method was provided but genesis data was provided")
|
errNoMethodWithGenesis = errors.New("no method was provided but genesis data was provided")
|
||||||
errCreatingTransaction = errors.New("problem while creating transaction")
|
errCreatingTransaction = errors.New("problem while creating transaction")
|
||||||
errNoDestination = errors.New("call is missing field 'stakeDestination'")
|
errNoDestination = errors.New("call is missing field 'stakeDestination'")
|
||||||
errNoSource = errors.New("call is missing field 'stakeSource'")
|
errNoSource = errors.New("call is missing field 'stakeSource'")
|
||||||
errGetStakeSource = errors.New("couldn't get account specified in '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
|
// Service defines the API calls that can be made to the platform chain
|
||||||
type Service struct{ vm *VM }
|
type Service struct{ vm *VM }
|
||||||
|
|
||||||
|
@ -319,7 +303,7 @@ type ListAccountsReply struct {
|
||||||
|
|
||||||
// ListAccounts lists all of the accounts controlled by [args.Username]
|
// ListAccounts lists all of the accounts controlled by [args.Username]
|
||||||
func (service *Service) ListAccounts(_ *http.Request, args *ListAccountsArgs, reply *ListAccountsReply) error {
|
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
|
// db holds the user's info that pertains to the Platform Chain
|
||||||
userDB, err := service.vm.Ctx.Keystore.GetDatabase(args.Username, args.Password)
|
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
|
// The account's ID is [privKey].PublicKey().Address(), where [privKey] is a
|
||||||
// private key controlled by the user.
|
// private key controlled by the user.
|
||||||
func (service *Service) CreateAccount(_ *http.Request, args *CreateAccountArgs, reply *CreateAccountReply) error {
|
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 holds the user's info that pertains to the Platform Chain
|
||||||
userDB, err := service.vm.Ctx.Keystore.GetDatabase(args.Username, args.Password)
|
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
|
// AddDefaultSubnetValidator returns an unsigned transaction to add a validator to the default subnet
|
||||||
// The returned unsigned transaction should be signed using Sign()
|
// The returned unsigned transaction should be signed using Sign()
|
||||||
func (service *Service) AddDefaultSubnetValidator(_ *http.Request, args *AddDefaultSubnetValidatorArgs, reply *CreateTxResponse) error {
|
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
|
if args.ID.IsZero() { // If ID unspecified, use this node's ID as validator ID
|
||||||
args.ID = service.vm.Ctx.NodeID
|
args.ID = service.vm.Ctx.NodeID
|
||||||
|
@ -497,7 +481,7 @@ type AddDefaultSubnetDelegatorArgs struct {
|
||||||
// to the default subnet
|
// to the default subnet
|
||||||
// The returned unsigned transaction should be signed using Sign()
|
// The returned unsigned transaction should be signed using Sign()
|
||||||
func (service *Service) AddDefaultSubnetDelegator(_ *http.Request, args *AddDefaultSubnetDelegatorArgs, reply *CreateTxResponse) error {
|
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
|
if args.ID.IsZero() { // If ID unspecified, use this node's ID as validator ID
|
||||||
args.ID = service.vm.Ctx.NodeID
|
args.ID = service.vm.Ctx.NodeID
|
||||||
|
@ -679,7 +663,7 @@ type SignResponse struct {
|
||||||
|
|
||||||
// Sign [args.bytes]
|
// Sign [args.bytes]
|
||||||
func (service *Service) Sign(_ *http.Request, args *SignArgs, reply *SignResponse) error {
|
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
|
// Get the key of the Signer
|
||||||
db, err := service.vm.Ctx.Keystore.GetDatabase(args.Username, args.Password)
|
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)
|
genTx.Tx, err = service.signAddNonDefaultSubnetValidatorTx(tx, key)
|
||||||
case *CreateSubnetTx:
|
case *CreateSubnetTx:
|
||||||
genTx.Tx, err = service.signCreateSubnetTx(tx, key)
|
genTx.Tx, err = service.signCreateSubnetTx(tx, key)
|
||||||
|
case *CreateChainTx:
|
||||||
|
genTx.Tx, err = service.signCreateChainTx(tx, key)
|
||||||
case *ExportTx:
|
case *ExportTx:
|
||||||
genTx.Tx, err = service.signExportTx(tx, key)
|
genTx.Tx, err = service.signExportTx(tx, key)
|
||||||
default:
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -725,7 +711,7 @@ func (service *Service) Sign(_ *http.Request, args *SignArgs, reply *SignRespons
|
||||||
|
|
||||||
// Sign [unsigned] with [key]
|
// Sign [unsigned] with [key]
|
||||||
func (service *Service) signAddDefaultSubnetValidatorTx(tx *addDefaultSubnetValidatorTx, key *crypto.PrivateKeySECP256K1R) (*addDefaultSubnetValidatorTx, error) {
|
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?
|
// TODO: Should we check if tx is already signed?
|
||||||
unsignedIntf := interface{}(&tx.UnsignedAddDefaultSubnetValidatorTx)
|
unsignedIntf := interface{}(&tx.UnsignedAddDefaultSubnetValidatorTx)
|
||||||
|
@ -748,7 +734,7 @@ func (service *Service) signAddDefaultSubnetValidatorTx(tx *addDefaultSubnetVali
|
||||||
|
|
||||||
// Sign [unsigned] with [key]
|
// Sign [unsigned] with [key]
|
||||||
func (service *Service) signAddDefaultSubnetDelegatorTx(tx *addDefaultSubnetDelegatorTx, key *crypto.PrivateKeySECP256K1R) (*addDefaultSubnetDelegatorTx, error) {
|
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?
|
// TODO: Should we check if tx is already signed?
|
||||||
unsignedIntf := interface{}(&tx.UnsignedAddDefaultSubnetDelegatorTx)
|
unsignedIntf := interface{}(&tx.UnsignedAddDefaultSubnetDelegatorTx)
|
||||||
|
@ -771,7 +757,7 @@ func (service *Service) signAddDefaultSubnetDelegatorTx(tx *addDefaultSubnetDele
|
||||||
|
|
||||||
// Sign [xt] with [key]
|
// Sign [xt] with [key]
|
||||||
func (service *Service) signCreateSubnetTx(tx *CreateSubnetTx, key *crypto.PrivateKeySECP256K1R) (*CreateSubnetTx, error) {
|
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?
|
// TODO: Should we check if tx is already signed?
|
||||||
unsignedIntf := interface{}(&tx.UnsignedCreateSubnetTx)
|
unsignedIntf := interface{}(&tx.UnsignedCreateSubnetTx)
|
||||||
|
@ -822,7 +808,7 @@ func (service *Service) signExportTx(tx *ExportTx, key *crypto.PrivateKeySECP256
|
||||||
// Sorts tx.ControlSigs before returning
|
// Sorts tx.ControlSigs before returning
|
||||||
// Assumes each element of tx.ControlSigs is actually a signature, not just empty bytes
|
// 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) {
|
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
|
// Compute the byte repr. of the unsigned tx and the signature of [key] over it
|
||||||
unsignedIntf := interface{}(&tx.UnsignedAddNonDefaultSubnetValidatorTx)
|
unsignedIntf := interface{}(&tx.UnsignedAddNonDefaultSubnetValidatorTx)
|
||||||
|
@ -1003,6 +989,59 @@ func (service *Service) CreateImportTx(_ *http.Request, args *CreateImportTxArgs
|
||||||
return nil
|
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
|
// IssueTxArgs are the arguments to IssueTx
|
||||||
type IssueTxArgs struct {
|
type IssueTxArgs struct {
|
||||||
// Tx being sent to the network
|
// Tx being sent to the network
|
||||||
|
@ -1017,6 +1056,8 @@ type IssueTxResponse struct {
|
||||||
|
|
||||||
// IssueTx issues the transaction [args.Tx] to the network
|
// IssueTx issues the transaction [args.Tx] to the network
|
||||||
func (service *Service) IssueTx(_ *http.Request, args *IssueTxArgs, response *IssueTxResponse) error {
|
func (service *Service) IssueTx(_ *http.Request, args *IssueTxArgs, response *IssueTxResponse) error {
|
||||||
|
service.vm.Ctx.Log.Debug("issueTx called")
|
||||||
|
|
||||||
genTx := genericTx{}
|
genTx := genericTx{}
|
||||||
if err := Codec.Unmarshal(args.Tx.Bytes, &genTx); err != nil {
|
if err := Codec.Unmarshal(args.Tx.Bytes, &genTx); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -1057,6 +1098,9 @@ func (service *Service) IssueTx(_ *http.Request, args *IssueTxArgs, response *Is
|
||||||
|
|
||||||
// CreateBlockchainArgs is the arguments for calling CreateBlockchain
|
// CreateBlockchainArgs is the arguments for calling CreateBlockchain
|
||||||
type CreateBlockchainArgs struct {
|
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
|
// ID of the VM the new blockchain is running
|
||||||
VMID string `json:"vmID"`
|
VMID string `json:"vmID"`
|
||||||
|
|
||||||
|
@ -1066,26 +1110,18 @@ type CreateBlockchainArgs struct {
|
||||||
// Human-readable name for the new blockchain, not necessarily unique
|
// Human-readable name for the new blockchain, not necessarily unique
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
|
|
||||||
// To generate the byte representation of the genesis data for this blockchain,
|
// Next unused nonce of the account paying the transaction fee
|
||||||
// a POST request with body [GenesisData] is made to the API method whose name is [Method], whose
|
PayerNonce json.Uint64 `json:"payerNonce"`
|
||||||
// endpoint is [Endpoint]. See Platform Chain documentation for more info and examples.
|
|
||||||
Method string `json:"method"`
|
// Genesis state of the blockchain being created
|
||||||
Endpoint string `json:"endpoint"`
|
GenesisData formatting.CB58 `json:"genesisData"`
|
||||||
GenesisData interface{} `json:"genesisData"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateGenesisReply is the reply from a call to CreateGenesis
|
// CreateBlockchain returns an unsigned transaction to create a new blockchain
|
||||||
type CreateGenesisReply struct {
|
// Must be signed with the Subnet's control keys and with a key that pays the transaction fee before issuance
|
||||||
Bytes formatting.CB58 `json:"bytes"`
|
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)
|
vmID, err := service.vm.chainManager.LookupVM(args.VMID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("no VM with ID '%s' found", args.VMID)
|
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)
|
fxIDs = append(fxIDs, fxID)
|
||||||
}
|
}
|
||||||
|
// If creating AVM instance, use secp256k1fx
|
||||||
genesisBytes := []byte(nil)
|
// TODO: Document FXs and have user specify them in API call
|
||||||
if args.Method != "" {
|
fxIDsSet := ids.Set{}
|
||||||
buf, err := json2.EncodeClientRequest(args.Method, args.GenesisData)
|
fxIDsSet.Add(fxIDs...)
|
||||||
if err != nil {
|
if vmID.Equals(avm.ID) && !fxIDsSet.Contains(secp256k1fx.ID) {
|
||||||
return fmt.Errorf("problem building blockchain genesis state: %w", err)
|
fxIDs = append(fxIDs, secp256k1fx.ID)
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Should use the key store to sign this transaction.
|
if args.SubnetID.Equals(DefaultSubnetID) {
|
||||||
// TODO: Nonce shouldn't always be 0
|
return errDSCantValidate
|
||||||
tx, err := service.vm.newCreateChainTx(0, genesisBytes, vmID, fxIDs, args.Name, service.vm.Ctx.NetworkID, key)
|
}
|
||||||
|
|
||||||
|
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 {
|
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
|
response.UnsignedTx.Bytes = txBytes
|
||||||
service.vm.unissuedDecisionTxs = append(service.vm.unissuedDecisionTxs, tx)
|
|
||||||
service.vm.resetTimer()
|
|
||||||
|
|
||||||
reply.BlockchainID = tx.ID()
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1158,6 +1189,8 @@ type GetBlockchainStatusReply struct {
|
||||||
|
|
||||||
// GetBlockchainStatus gets the status of a blockchain with the ID [args.BlockchainID].
|
// GetBlockchainStatus gets the status of a blockchain with the ID [args.BlockchainID].
|
||||||
func (service *Service) GetBlockchainStatus(_ *http.Request, args *GetBlockchainStatusArgs, reply *GetBlockchainStatusReply) error {
|
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)
|
_, err := service.vm.chainManager.Lookup(args.BlockchainID)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
reply.Status = Validating
|
reply.Status = Validating
|
||||||
|
@ -1212,3 +1245,100 @@ func (service *Service) chainExists(blockID ids.ID, chainID ids.ID) (bool, error
|
||||||
|
|
||||||
return false, nil
|
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) {
|
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{}
|
args := CreateBlockchainArgs{}
|
||||||
err := json.Unmarshal([]byte(jsonString), &args)
|
err := json.Unmarshal([]byte(jsonString), &args)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -17,6 +17,7 @@ import (
|
||||||
|
|
||||||
var (
|
var (
|
||||||
errEmptyAccountAddress = errors.New("account has empty address")
|
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
|
// 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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the blockchains that exist
|
// get all the blockchains that exist
|
||||||
func (vm *VM) getChains(db database.Database) ([]*CreateChainTx, error) {
|
func (vm *VM) getChains(db database.Database) ([]*CreateChainTx, error) {
|
||||||
chainsInterface, err := vm.State.Get(db, chainsTypeID, chainsKey)
|
chainsInterface, err := vm.State.Get(db, chainsTypeID, chainsKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -154,12 +155,26 @@ func (vm *VM) getChains(db database.Database) ([]*CreateChainTx, error) {
|
||||||
}
|
}
|
||||||
chains, ok := chainsInterface.([]*CreateChainTx)
|
chains, ok := chainsInterface.([]*CreateChainTx)
|
||||||
if !ok {
|
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 nil, errDBChains
|
||||||
}
|
}
|
||||||
return chains, nil
|
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
|
// put the list of blockchains that exist to database
|
||||||
func (vm *VM) putChains(db database.Database, chains createChainList) error {
|
func (vm *VM) putChains(db database.Database, chains createChainList) error {
|
||||||
if err := vm.State.Put(db, chainsTypeID, chainsKey, chains); err != nil {
|
if err := vm.State.Put(db, chainsTypeID, chainsKey, chains); err != nil {
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/ava-labs/gecko/ids"
|
"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/formatting"
|
||||||
"github.com/ava-labs/gecko/utils/json"
|
"github.com/ava-labs/gecko/utils/json"
|
||||||
)
|
)
|
||||||
|
@ -74,11 +75,13 @@ type APIDefaultSubnetValidator struct {
|
||||||
// [VMID] is the ID of the VM this chain runs.
|
// [VMID] is the ID of the VM this chain runs.
|
||||||
// [FxIDs] are the IDs of the Fxs the chain supports.
|
// [FxIDs] are the IDs of the Fxs the chain supports.
|
||||||
// [Name] is a human-readable, non-unique name for the chain.
|
// [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 {
|
type APIChain struct {
|
||||||
GenesisData formatting.CB58 `json:"genesisData"`
|
GenesisData formatting.CB58 `json:"genesisData"`
|
||||||
VMID ids.ID `json:"vmID"`
|
VMID ids.ID `json:"vmID"`
|
||||||
FxIDs []ids.ID `json:"fxIDs"`
|
FxIDs []ids.ID `json:"fxIDs"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
|
SubnetID ids.ID `json:"subnetID"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// BuildGenesisArgs are the arguments used to create
|
// BuildGenesisArgs are the arguments used to create
|
||||||
|
@ -134,8 +137,8 @@ func (*StaticService) BuildGenesis(_ *http.Request, args *BuildGenesisArgs, repl
|
||||||
return errAccountHasNoValue
|
return errAccountHasNoValue
|
||||||
}
|
}
|
||||||
accounts = append(accounts, newAccount(
|
accounts = append(accounts, newAccount(
|
||||||
account.Address, // ID
|
account.Address, // ID
|
||||||
0, // nonce
|
0, // nonce
|
||||||
uint64(account.Balance), // balance
|
uint64(account.Balance), // balance
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
@ -182,12 +185,15 @@ func (*StaticService) BuildGenesis(_ *http.Request, args *BuildGenesisArgs, repl
|
||||||
tx := &CreateChainTx{
|
tx := &CreateChainTx{
|
||||||
UnsignedCreateChainTx: UnsignedCreateChainTx{
|
UnsignedCreateChainTx: UnsignedCreateChainTx{
|
||||||
NetworkID: uint32(args.NetworkID),
|
NetworkID: uint32(args.NetworkID),
|
||||||
|
SubnetID: chain.SubnetID,
|
||||||
Nonce: 0,
|
Nonce: 0,
|
||||||
ChainName: chain.Name,
|
ChainName: chain.Name,
|
||||||
VMID: chain.VMID,
|
VMID: chain.VMID,
|
||||||
FxIDs: chain.FxIDs,
|
FxIDs: chain.FxIDs,
|
||||||
GenesisData: chain.GenesisData.Bytes,
|
GenesisData: chain.GenesisData.Bytes,
|
||||||
},
|
},
|
||||||
|
ControlSigs: [][crypto.SECP256K1RSigLen]byte{},
|
||||||
|
PayerSig: [crypto.SECP256K1RSigLen]byte{},
|
||||||
}
|
}
|
||||||
if err := tx.initialize(nil); err != nil {
|
if err := tx.initialize(nil); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -4,114 +4,12 @@
|
||||||
package platformvm
|
package platformvm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/ava-labs/gecko/ids"
|
"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/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) {
|
func TestBuildGenesisInvalidAccountBalance(t *testing.T) {
|
||||||
id, _ := ids.ShortFromString("8CrVPQZ4VSqgL8zTdvL14G8HqAfrBr4z")
|
id, _ := ids.ShortFromString("8CrVPQZ4VSqgL8zTdvL14G8HqAfrBr4z")
|
||||||
account := APIAccount{
|
account := APIAccount{
|
||||||
|
|
|
@ -151,8 +151,13 @@ func init() {
|
||||||
type VM struct {
|
type VM struct {
|
||||||
*core.SnowmanVM
|
*core.SnowmanVM
|
||||||
|
|
||||||
|
// Node's validator manager
|
||||||
|
// Maps Subnets --> nodes in the Subnet HEAD
|
||||||
validators validators.Manager
|
validators validators.Manager
|
||||||
|
|
||||||
|
// true if the node is being run with staking enabled
|
||||||
|
stakingEnabled bool
|
||||||
|
|
||||||
// The node's chain manager
|
// The node's chain manager
|
||||||
chainManager chains.Manager
|
chainManager chains.Manager
|
||||||
|
|
||||||
|
@ -296,8 +301,8 @@ func (vm *VM) Initialize(
|
||||||
})
|
})
|
||||||
go ctx.Log.RecoverAndPanic(vm.timer.Dispatch)
|
go ctx.Log.RecoverAndPanic(vm.timer.Dispatch)
|
||||||
|
|
||||||
if err := vm.updateValidators(DefaultSubnetID); err != nil {
|
if err := vm.initSubnets(); err != nil {
|
||||||
ctx.Log.Error("failed to initialize the current validator set: %s", err)
|
ctx.Log.Error("failed to initialize Subnets: %s", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -313,27 +318,67 @@ func (vm *VM) Initialize(
|
||||||
return nil
|
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 {
|
func (vm *VM) initBlockchains() error {
|
||||||
vm.Ctx.Log.Verbo("platform chain initializing existing blockchains")
|
vm.Ctx.Log.Info("initializing blockchains")
|
||||||
existingChains, err := vm.getChains(vm.DB)
|
blockchains, err := vm.getChains(vm.DB) // get blockchains that exist
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for _, chain := range existingChains { // Create each blockchain
|
|
||||||
chainParams := chains.ChainParameters{
|
for _, chain := range blockchains {
|
||||||
ID: chain.ID(),
|
vm.createChain(chain)
|
||||||
GenesisData: chain.GenesisData,
|
|
||||||
VMAlias: chain.VMID.String(),
|
|
||||||
}
|
|
||||||
for _, fxID := range chain.FxIDs {
|
|
||||||
chainParams.FxAliases = append(chainParams.FxAliases, fxID.String())
|
|
||||||
}
|
|
||||||
vm.chainManager.CreateChain(chainParams)
|
|
||||||
}
|
}
|
||||||
return nil
|
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
|
// Shutdown this blockchain
|
||||||
func (vm *VM) Shutdown() {
|
func (vm *VM) Shutdown() {
|
||||||
vm.timer.Stop()
|
vm.timer.Stop()
|
||||||
|
@ -663,13 +708,16 @@ func (vm *VM) nextSubnetValidatorChangeTime(db database.Database, subnetID ids.I
|
||||||
// Returns:
|
// Returns:
|
||||||
// 1) The validator set of subnet with ID [subnetID] when timestamp is advanced to [timestamp]
|
// 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]
|
// 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.
|
// Note that this method will not remove validators from the current validator set of the default subnet.
|
||||||
// That happens in reward blocks.
|
// 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]
|
// remove validators whose end time <= [timestamp]
|
||||||
current, err = vm.getCurrentValidators(db, subnetID)
|
current, err = vm.getCurrentValidators(db, subnetID)
|
||||||
if err != nil {
|
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
|
if !subnetID.Equals(DefaultSubnetID) { // validators of default subnet removed in rewardValidatorTxs, not here
|
||||||
for current.Len() > 0 {
|
for current.Len() > 0 {
|
||||||
|
@ -678,11 +726,12 @@ func (vm *VM) calculateValidators(db database.Database, timestamp time.Time, sub
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
current.Remove()
|
current.Remove()
|
||||||
|
stopped.Add(next.Vdr().ID())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pending, err = vm.getPendingValidators(db, subnetID)
|
pending, err = vm.getPendingValidators(db, subnetID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, nil, nil, err
|
||||||
}
|
}
|
||||||
for pending.Len() > 0 {
|
for pending.Len() > 0 {
|
||||||
nextTx := pending.Peek() // pending staker with earliest start time
|
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.Push(current, nextTx)
|
||||||
heap.Pop(pending)
|
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 {
|
func (vm *VM) getValidators(validatorEvents *EventHeap) []validators.Validator {
|
||||||
|
@ -720,10 +770,12 @@ func (vm *VM) getValidators(validatorEvents *EventHeap) []validators.Validator {
|
||||||
return vdrList
|
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 {
|
func (vm *VM) updateValidators(subnetID ids.ID) error {
|
||||||
validatorSet, ok := vm.validators.GetValidatorSet(subnetID)
|
validatorSet, subnetInitialized := vm.validators.GetValidatorSet(subnetID)
|
||||||
if !ok {
|
if !subnetInitialized { // validator manager doesn't know about this subnet yet
|
||||||
return fmt.Errorf("couldn't get the validator sampler of the %s subnet", subnetID)
|
validatorSet = validators.NewSet()
|
||||||
|
vm.validators.PutValidatorSet(subnetID, validatorSet)
|
||||||
}
|
}
|
||||||
|
|
||||||
currentValidators, err := vm.getCurrentValidators(vm.DB, subnetID)
|
currentValidators, err := vm.getCurrentValidators(vm.DB, subnetID)
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/ava-labs/gecko/chains"
|
||||||
"github.com/ava-labs/gecko/chains/atomic"
|
"github.com/ava-labs/gecko/chains/atomic"
|
||||||
"github.com/ava-labs/gecko/database/memdb"
|
"github.com/ava-labs/gecko/database/memdb"
|
||||||
"github.com/ava-labs/gecko/ids"
|
"github.com/ava-labs/gecko/ids"
|
||||||
|
@ -39,16 +40,17 @@ var (
|
||||||
// each key corresponds to an account that has $AVA and a genesis validator
|
// each key corresponds to an account that has $AVA and a genesis validator
|
||||||
keys []*crypto.PrivateKeySECP256K1R
|
keys []*crypto.PrivateKeySECP256K1R
|
||||||
|
|
||||||
// amount all genesis validators stake
|
// amount all genesis validators stake in defaultVM
|
||||||
defaultStakeAmount uint64
|
defaultStakeAmount uint64
|
||||||
|
|
||||||
// balance of accounts that exist at genesis
|
// balance of accounts that exist at genesis in defaultVM
|
||||||
defaultBalance = 100 * MinimumStakeAmount
|
defaultBalance = 100 * MinimumStakeAmount
|
||||||
|
|
||||||
// At genesis this account has AVA and is validating the default subnet
|
// At genesis this account has AVA and is validating the default subnet
|
||||||
defaultKey *crypto.PrivateKeySECP256K1R
|
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
|
testSubnet1 *CreateSubnetTx
|
||||||
testSubnet1ControlKeys []*crypto.PrivateKeySECP256K1R
|
testSubnet1ControlKeys []*crypto.PrivateKeySECP256K1R
|
||||||
)
|
)
|
||||||
|
@ -116,7 +118,8 @@ func defaultVM() *VM {
|
||||||
}
|
}
|
||||||
|
|
||||||
vm := &VM{
|
vm := &VM{
|
||||||
SnowmanVM: &core.SnowmanVM{},
|
SnowmanVM: &core.SnowmanVM{},
|
||||||
|
chainManager: chains.MockManager{},
|
||||||
}
|
}
|
||||||
|
|
||||||
defaultSubnet := validators.NewSet()
|
defaultSubnet := validators.NewSet()
|
||||||
|
@ -136,7 +139,7 @@ func defaultVM() *VM {
|
||||||
testNetworkID,
|
testNetworkID,
|
||||||
0,
|
0,
|
||||||
[]ids.ShortID{keys[0].PublicKey().Address(), keys[1].PublicKey().Address(), keys[2].PublicKey().Address()}, // control keys are keys[0], keys[1], keys[2]
|
[]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],
|
keys[0],
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -765,11 +768,13 @@ func TestCreateChain(t *testing.T) {
|
||||||
|
|
||||||
tx, err := vm.newCreateChainTx(
|
tx, err := vm.newCreateChainTx(
|
||||||
defaultNonce+1,
|
defaultNonce+1,
|
||||||
|
testSubnet1.id,
|
||||||
nil,
|
nil,
|
||||||
timestampvm.ID,
|
timestampvm.ID,
|
||||||
nil,
|
nil,
|
||||||
"name ",
|
"name",
|
||||||
testNetworkID,
|
testNetworkID,
|
||||||
|
[]*crypto.PrivateKeySECP256K1R{testSubnet1ControlKeys[0], testSubnet1ControlKeys[1]},
|
||||||
keys[0],
|
keys[0],
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -806,7 +811,7 @@ func TestCreateChain(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify tx fee was deducted
|
// 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 {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,10 +74,6 @@ func init() {
|
||||||
networkID, err := genesis.NetworkID(*networkName)
|
networkID, err := genesis.NetworkID(*networkName)
|
||||||
errs.Add(err)
|
errs.Add(err)
|
||||||
|
|
||||||
if networkID != genesis.LocalID {
|
|
||||||
errs.Add(fmt.Errorf("the only supported networkID is: %s", genesis.LocalName))
|
|
||||||
}
|
|
||||||
|
|
||||||
config.NetworkID = networkID
|
config.NetworkID = networkID
|
||||||
|
|
||||||
// Remote:
|
// Remote:
|
||||||
|
|
Loading…
Reference in New Issue