Merge branch 'cascade' into latency

This commit is contained in:
StephenButtolph 2020-04-04 02:11:12 -04:00
commit 4e20130db8
266 changed files with 12516 additions and 5617 deletions

5
.gitignore vendored
View File

@ -18,6 +18,9 @@ awscpu
# Output of the go coverage tool, specifically when used with LiteIDE # Output of the go coverage tool, specifically when used with LiteIDE
*.out *.out
# ignore GoLand metafiles directory
.idea/
*logs/ *logs/
.vscode* .vscode*
@ -42,4 +45,4 @@ db*
bin/ bin/
build/ build/
*/mykey/staker.* keys/staker.*

View File

@ -54,7 +54,7 @@ The Gecko binary, named `ava`, is in the `build` directory.
- Build the docker image of latest gecko branch by `scripts/build_image.sh`. - Build the docker image of latest gecko branch by `scripts/build_image.sh`.
- Check the built image by `docker image ls`, you should see some image tagged - Check the built image by `docker image ls`, you should see some image tagged
`gecko-xxxxxxxx`, where `xxxxxxxx` is the commit id of the Gecko source it was built from. `gecko-xxxxxxxx`, where `xxxxxxxx` is the commit id of the Gecko source it was built from.
- Test Gecko by `docker run -ti -p 9651:9651 gecko-xxxxxxxx /gecko/build/ava - Test Gecko by `docker run -ti -p 9650:9650 -p 9651:9651 gecko-xxxxxxxx /gecko/build/ava
--public-ip=127.0.0.1 --snow-sample-size=1 --snow-quorum-size=1 --staking-tls-enabled=false`. (For a production deployment, --public-ip=127.0.0.1 --snow-sample-size=1 --snow-quorum-size=1 --staking-tls-enabled=false`. (For a production deployment,
you may want to extend the docker image with required credentials for you may want to extend the docker image with required credentials for
staking and TLS.) staking and TLS.)

View File

@ -21,10 +21,30 @@ import (
"github.com/ava-labs/gecko/vms/components/codec" "github.com/ava-labs/gecko/vms/components/codec"
jsoncodec "github.com/ava-labs/gecko/utils/json" jsoncodec "github.com/ava-labs/gecko/utils/json"
zxcvbn "github.com/nbutton23/zxcvbn-go"
)
const (
// maxUserPassLen is the maximum length of the username or password allowed
maxUserPassLen = 1024
// requiredPassScore defines the score a password must achieve to be accepted
// as a password with strong characteristics by the zxcvbn package
//
// The scoring mechanism defined is as follows;
//
// 0 # too guessable: risky password. (guesses < 10^3)
// 1 # very guessable: protection from throttled online attacks. (guesses < 10^6)
// 2 # somewhat guessable: protection from unthrottled online attacks. (guesses < 10^8)
// 3 # safely unguessable: moderate protection from offline slow-hash scenario. (guesses < 10^10)
// 4 # very unguessable: strong protection from offline slow-hash scenario. (guesses >= 10^10)
requiredPassScore = 2
) )
var ( var (
errEmptyUsername = errors.New("username can't be the empty string") errEmptyUsername = errors.New("username can't be the empty string")
errUserPassMaxLength = fmt.Errorf("CreateUser call rejected due to username or password exceeding maximum length of %d chars", maxUserPassLen)
errWeakPassword = errors.New("Failed to create user as the given password is too weak. A stronger password is one of 8 or more characters containing attributes of upper and lowercase letters, numbers, and/or special characters")
) )
// KeyValuePair ... // KeyValuePair ...
@ -114,7 +134,11 @@ func (ks *Keystore) CreateUser(_ *http.Request, args *CreateUserArgs, reply *Cre
ks.lock.Lock() ks.lock.Lock()
defer ks.lock.Unlock() defer ks.lock.Unlock()
ks.log.Verbo("CreateUser called with %s", args.Username) ks.log.Verbo("CreateUser called with %.*s", maxUserPassLen, args.Username)
if len(args.Username) > maxUserPassLen || len(args.Password) > maxUserPassLen {
return errUserPassMaxLength
}
if args.Username == "" { if args.Username == "" {
return errEmptyUsername return errEmptyUsername
@ -123,6 +147,10 @@ func (ks *Keystore) CreateUser(_ *http.Request, args *CreateUserArgs, reply *Cre
return fmt.Errorf("user already exists: %s", args.Username) return fmt.Errorf("user already exists: %s", args.Username)
} }
if zxcvbn.PasswordStrength(args.Password, nil).Score < requiredPassScore {
return errWeakPassword
}
usr := &User{} usr := &User{}
if err := usr.Initialize(args.Password); err != nil { if err := usr.Initialize(args.Password); err != nil {
return err return err

View File

@ -5,6 +5,8 @@ package keystore
import ( import (
"bytes" "bytes"
"fmt"
"math/rand"
"testing" "testing"
"github.com/ava-labs/gecko/database/memdb" "github.com/ava-labs/gecko/database/memdb"
@ -12,6 +14,12 @@ import (
"github.com/ava-labs/gecko/utils/logging" "github.com/ava-labs/gecko/utils/logging"
) )
var (
// strongPassword defines a password used for the following tests that
// scores high enough to pass the password strength scoring system
strongPassword = "N_+=_jJ;^(<;{4,:*m6CET}'&N;83FYK.wtNpwp-Jt"
)
func TestServiceListNoUsers(t *testing.T) { func TestServiceListNoUsers(t *testing.T) {
ks := Keystore{} ks := Keystore{}
ks.Initialize(logging.NoLog{}, memdb.New()) ks.Initialize(logging.NoLog{}, memdb.New())
@ -33,7 +41,7 @@ func TestServiceCreateUser(t *testing.T) {
reply := CreateUserReply{} reply := CreateUserReply{}
if err := ks.CreateUser(nil, &CreateUserArgs{ if err := ks.CreateUser(nil, &CreateUserArgs{
Username: "bob", Username: "bob",
Password: "launch", Password: strongPassword,
}, &reply); err != nil { }, &reply); err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -56,6 +64,78 @@ func TestServiceCreateUser(t *testing.T) {
} }
} }
// genStr returns a string of given length
func genStr(n int) string {
b := make([]byte, n)
rand.Read(b)
return fmt.Sprintf("%x", b)[:n]
}
// TestServiceCreateUserArgsChecks generates excessively long usernames or
// passwords to assure the santity checks on string length are not exceeded
func TestServiceCreateUserArgsCheck(t *testing.T) {
ks := Keystore{}
ks.Initialize(logging.NoLog{}, memdb.New())
{
reply := CreateUserReply{}
err := ks.CreateUser(nil, &CreateUserArgs{
Username: genStr(maxUserPassLen + 1),
Password: strongPassword,
}, &reply)
if reply.Success || err != errUserPassMaxLength {
t.Fatal("User was created when it should have been rejected due to too long a Username, err =", err)
}
}
{
reply := CreateUserReply{}
err := ks.CreateUser(nil, &CreateUserArgs{
Username: "shortuser",
Password: genStr(maxUserPassLen + 1),
}, &reply)
if reply.Success || err != errUserPassMaxLength {
t.Fatal("User was created when it should have been rejected due to too long a Password, err =", err)
}
}
{
reply := ListUsersReply{}
if err := ks.ListUsers(nil, &ListUsersArgs{}, &reply); err != nil {
t.Fatal(err)
}
if len(reply.Users) > 0 {
t.Fatalf("A user exists when there should be none")
}
}
}
// TestServiceCreateUserWeakPassword tests creating a new user with a weak
// password to ensure the password strength check is working
func TestServiceCreateUserWeakPassword(t *testing.T) {
ks := Keystore{}
ks.Initialize(logging.NoLog{}, memdb.New())
{
reply := CreateUserReply{}
err := ks.CreateUser(nil, &CreateUserArgs{
Username: "bob",
Password: "weak",
}, &reply)
if err != errWeakPassword {
t.Error("Unexpected error occurred when testing weak password:", err)
}
if reply.Success {
t.Fatal("User was created when it should have been rejected due to weak password")
}
}
}
func TestServiceCreateDuplicate(t *testing.T) { func TestServiceCreateDuplicate(t *testing.T) {
ks := Keystore{} ks := Keystore{}
ks.Initialize(logging.NoLog{}, memdb.New()) ks.Initialize(logging.NoLog{}, memdb.New())
@ -64,7 +144,7 @@ func TestServiceCreateDuplicate(t *testing.T) {
reply := CreateUserReply{} reply := CreateUserReply{}
if err := ks.CreateUser(nil, &CreateUserArgs{ if err := ks.CreateUser(nil, &CreateUserArgs{
Username: "bob", Username: "bob",
Password: "launch", Password: strongPassword,
}, &reply); err != nil { }, &reply); err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -77,7 +157,7 @@ func TestServiceCreateDuplicate(t *testing.T) {
reply := CreateUserReply{} reply := CreateUserReply{}
if err := ks.CreateUser(nil, &CreateUserArgs{ if err := ks.CreateUser(nil, &CreateUserArgs{
Username: "bob", Username: "bob",
Password: "launch!", Password: strongPassword,
}, &reply); err == nil { }, &reply); err == nil {
t.Fatalf("Should have errored due to the username already existing") t.Fatalf("Should have errored due to the username already existing")
} }
@ -90,7 +170,7 @@ func TestServiceCreateUserNoName(t *testing.T) {
reply := CreateUserReply{} reply := CreateUserReply{}
if err := ks.CreateUser(nil, &CreateUserArgs{ if err := ks.CreateUser(nil, &CreateUserArgs{
Password: "launch", Password: strongPassword,
}, &reply); err == nil { }, &reply); err == nil {
t.Fatalf("Shouldn't have allowed empty username") t.Fatalf("Shouldn't have allowed empty username")
} }
@ -104,7 +184,7 @@ func TestServiceUseBlockchainDB(t *testing.T) {
reply := CreateUserReply{} reply := CreateUserReply{}
if err := ks.CreateUser(nil, &CreateUserArgs{ if err := ks.CreateUser(nil, &CreateUserArgs{
Username: "bob", Username: "bob",
Password: "launch", Password: strongPassword,
}, &reply); err != nil { }, &reply); err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -114,7 +194,7 @@ func TestServiceUseBlockchainDB(t *testing.T) {
} }
{ {
db, err := ks.GetDatabase(ids.Empty, "bob", "launch") db, err := ks.GetDatabase(ids.Empty, "bob", strongPassword)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -124,7 +204,7 @@ func TestServiceUseBlockchainDB(t *testing.T) {
} }
{ {
db, err := ks.GetDatabase(ids.Empty, "bob", "launch") db, err := ks.GetDatabase(ids.Empty, "bob", strongPassword)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -144,7 +224,7 @@ func TestServiceExportImport(t *testing.T) {
reply := CreateUserReply{} reply := CreateUserReply{}
if err := ks.CreateUser(nil, &CreateUserArgs{ if err := ks.CreateUser(nil, &CreateUserArgs{
Username: "bob", Username: "bob",
Password: "launch", Password: strongPassword,
}, &reply); err != nil { }, &reply); err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -154,7 +234,7 @@ func TestServiceExportImport(t *testing.T) {
} }
{ {
db, err := ks.GetDatabase(ids.Empty, "bob", "launch") db, err := ks.GetDatabase(ids.Empty, "bob", strongPassword)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -166,7 +246,7 @@ func TestServiceExportImport(t *testing.T) {
exportReply := ExportUserReply{} exportReply := ExportUserReply{}
if err := ks.ExportUser(nil, &ExportUserArgs{ if err := ks.ExportUser(nil, &ExportUserArgs{
Username: "bob", Username: "bob",
Password: "launch", Password: strongPassword,
}, &exportReply); err != nil { }, &exportReply); err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -178,7 +258,7 @@ func TestServiceExportImport(t *testing.T) {
reply := ImportUserReply{} reply := ImportUserReply{}
if err := newKS.ImportUser(nil, &ImportUserArgs{ if err := newKS.ImportUser(nil, &ImportUserArgs{
Username: "bob", Username: "bob",
Password: "launch", Password: strongPassword,
User: exportReply.User, User: exportReply.User,
}, &reply); err != nil { }, &reply); err != nil {
t.Fatal(err) t.Fatal(err)
@ -189,7 +269,7 @@ func TestServiceExportImport(t *testing.T) {
} }
{ {
db, err := newKS.GetDatabase(ids.Empty, "bob", "launch") db, err := newKS.GetDatabase(ids.Empty, "bob", strongPassword)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }

View File

@ -0,0 +1,28 @@
// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package atomic
import (
"github.com/ava-labs/gecko/database"
"github.com/ava-labs/gecko/ids"
)
// BlockchainSharedMemory provides the API for a blockchain to interact with
// shared memory of another blockchain
type BlockchainSharedMemory struct {
blockchainID ids.ID
sm *SharedMemory
}
// GetDatabase returns and locks the provided DB
func (bsm *BlockchainSharedMemory) GetDatabase(id ids.ID) database.Database {
sharedID := bsm.sm.sharedID(id, bsm.blockchainID)
return bsm.sm.GetDatabase(sharedID)
}
// ReleaseDatabase unlocks the provided DB
func (bsm *BlockchainSharedMemory) ReleaseDatabase(id ids.ID) {
sharedID := bsm.sm.sharedID(id, bsm.blockchainID)
bsm.sm.ReleaseDatabase(sharedID)
}

View File

@ -0,0 +1,34 @@
// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package atomic
import (
"bytes"
"testing"
"github.com/ava-labs/gecko/database/memdb"
"github.com/ava-labs/gecko/utils/logging"
)
func TestBlockchainSharedMemory(t *testing.T) {
sm := SharedMemory{}
sm.Initialize(logging.NoLog{}, memdb.New())
bsm0 := sm.NewBlockchainSharedMemory(blockchainID0)
bsm1 := sm.NewBlockchainSharedMemory(blockchainID1)
sharedDB0 := bsm0.GetDatabase(blockchainID1)
if err := sharedDB0.Put([]byte{1}, []byte{2}); err != nil {
t.Fatal(err)
}
bsm0.ReleaseDatabase(blockchainID1)
sharedDB1 := bsm1.GetDatabase(blockchainID0)
if value, err := sharedDB1.Get([]byte{1}); err != nil {
t.Fatal(err)
} else if !bytes.Equal(value, []byte{2}) {
t.Fatalf("database.Get Returned: 0x%x ; Expected: 0x%x", value, []byte{2})
}
bsm1.ReleaseDatabase(blockchainID0)
}

105
chains/atomic/memory.go Normal file
View File

@ -0,0 +1,105 @@
// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package atomic
import (
"bytes"
"sync"
"github.com/ava-labs/gecko/database"
"github.com/ava-labs/gecko/database/prefixdb"
"github.com/ava-labs/gecko/ids"
"github.com/ava-labs/gecko/utils/hashing"
"github.com/ava-labs/gecko/utils/logging"
"github.com/ava-labs/gecko/vms/components/codec"
)
type rcLock struct {
lock sync.Mutex
count int
}
// SharedMemory is the interface for shared memory inside a subnet
type SharedMemory struct {
lock sync.Mutex
log logging.Logger
codec codec.Codec
locks map[[32]byte]*rcLock
db database.Database
}
// Initialize the SharedMemory
func (sm *SharedMemory) Initialize(log logging.Logger, db database.Database) {
sm.log = log
sm.codec = codec.NewDefault()
sm.locks = make(map[[32]byte]*rcLock)
sm.db = db
}
// NewBlockchainSharedMemory returns a new BlockchainSharedMemory
func (sm *SharedMemory) NewBlockchainSharedMemory(id ids.ID) *BlockchainSharedMemory {
return &BlockchainSharedMemory{
blockchainID: id,
sm: sm,
}
}
// GetDatabase returns and locks the provided DB
func (sm *SharedMemory) GetDatabase(id ids.ID) database.Database {
lock := sm.makeLock(id)
lock.Lock()
return prefixdb.New(id.Bytes(), sm.db)
}
// ReleaseDatabase unlocks the provided DB
func (sm *SharedMemory) ReleaseDatabase(id ids.ID) {
lock := sm.releaseLock(id)
lock.Unlock()
}
func (sm *SharedMemory) makeLock(id ids.ID) *sync.Mutex {
sm.lock.Lock()
defer sm.lock.Unlock()
key := id.Key()
rc, exists := sm.locks[key]
if !exists {
rc = &rcLock{}
sm.locks[key] = rc
}
rc.count++
return &rc.lock
}
func (sm *SharedMemory) releaseLock(id ids.ID) *sync.Mutex {
sm.lock.Lock()
defer sm.lock.Unlock()
key := id.Key()
rc, exists := sm.locks[key]
if !exists {
panic("Attemping to free an unknown lock")
}
rc.count--
if rc.count == 0 {
delete(sm.locks, key)
}
return &rc.lock
}
// sharedID calculates the ID of the shared memory space
func (sm *SharedMemory) sharedID(id1, id2 ids.ID) ids.ID {
idKey1 := id1.Key()
idKey2 := id2.Key()
if bytes.Compare(idKey1[:], idKey2[:]) == 1 {
idKey1, idKey2 = idKey2, idKey1
}
combinedBytes, err := sm.codec.Marshal([2][32]byte{idKey1, idKey2})
sm.log.AssertNoError(err)
return ids.NewID(hashing.ComputeHash256Array(combinedBytes))
}

View File

@ -0,0 +1,69 @@
// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package atomic
import (
"testing"
"github.com/ava-labs/gecko/database/memdb"
"github.com/ava-labs/gecko/ids"
"github.com/ava-labs/gecko/utils/logging"
)
var (
blockchainID0 = ids.Empty.Prefix(0)
blockchainID1 = ids.Empty.Prefix(1)
)
func TestSharedMemorySharedID(t *testing.T) {
sm := SharedMemory{}
sm.Initialize(logging.NoLog{}, memdb.New())
sharedID0 := sm.sharedID(blockchainID0, blockchainID1)
sharedID1 := sm.sharedID(blockchainID1, blockchainID0)
if !sharedID0.Equals(sharedID1) {
t.Fatalf("SharedMemory.sharedID should be communitive")
}
}
func TestSharedMemoryMakeReleaseLock(t *testing.T) {
sm := SharedMemory{}
sm.Initialize(logging.NoLog{}, memdb.New())
sharedID := sm.sharedID(blockchainID0, blockchainID1)
lock0 := sm.makeLock(sharedID)
if lock1 := sm.makeLock(sharedID); lock0 != lock1 {
t.Fatalf("SharedMemory.makeLock should have returned the same lock")
}
sm.releaseLock(sharedID)
if lock2 := sm.makeLock(sharedID); lock0 != lock2 {
t.Fatalf("SharedMemory.makeLock should have returned the same lock")
}
sm.releaseLock(sharedID)
sm.releaseLock(sharedID)
if lock3 := sm.makeLock(sharedID); lock0 == lock3 {
t.Fatalf("SharedMemory.releaseLock should have returned freed the lock")
}
sm.releaseLock(sharedID)
}
func TestSharedMemoryUnknownFree(t *testing.T) {
sm := SharedMemory{}
sm.Initialize(logging.NoLog{}, memdb.New())
sharedID := sm.sharedID(blockchainID0, blockchainID1)
defer func() {
if recover() == nil {
t.Fatalf("Should have panicked due to an unknown free")
}
}()
sm.releaseLock(sharedID)
}

21
chains/atomic/writer.go Normal file
View File

@ -0,0 +1,21 @@
// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package atomic
import (
"github.com/ava-labs/gecko/database"
)
// WriteAll assumes all batches have the same underlying database. Batches
// should not be modified after being passed to this function.
func WriteAll(baseBatch database.Batch, batches ...database.Batch) error {
baseBatch = baseBatch.Inner()
for _, batch := range batches {
batch = batch.Inner()
if err := batch.Replay(baseBatch); err != nil {
return err
}
}
return baseBatch.Write()
}

View File

@ -0,0 +1,61 @@
// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package atomic
import (
"bytes"
"testing"
"github.com/ava-labs/gecko/database/memdb"
"github.com/ava-labs/gecko/database/prefixdb"
"github.com/ava-labs/gecko/database/versiondb"
"github.com/ava-labs/gecko/utils/logging"
)
func TestWriteAll(t *testing.T) {
baseDB := memdb.New()
prefixedDBChain := prefixdb.New([]byte{0}, baseDB)
prefixedDBSharedMemory := prefixdb.New([]byte{1}, baseDB)
sm := SharedMemory{}
sm.Initialize(logging.NoLog{}, prefixedDBSharedMemory)
sharedID := sm.sharedID(blockchainID0, blockchainID1)
sharedDB := sm.GetDatabase(sharedID)
writeDB0 := versiondb.New(prefixedDBChain)
writeDB1 := versiondb.New(sharedDB)
defer sm.ReleaseDatabase(sharedID)
if err := writeDB0.Put([]byte{1}, []byte{2}); err != nil {
t.Fatal(err)
}
if err := writeDB1.Put([]byte{2}, []byte{3}); err != nil {
t.Fatal(err)
}
batch0, err := writeDB0.CommitBatch()
if err != nil {
t.Fatal(err)
}
batch1, err := writeDB1.CommitBatch()
if err != nil {
t.Fatal(err)
}
if err := WriteAll(batch0, batch1); err != nil {
t.Fatal(err)
}
if value, err := prefixedDBChain.Get([]byte{1}); err != nil {
t.Fatal(err)
} else if !bytes.Equal(value, []byte{2}) {
t.Fatalf("database.Get Returned: 0x%x ; Expected: 0x%x", value, []byte{2})
} else if value, err := sharedDB.Get([]byte{2}); err != nil {
t.Fatal(err)
} else if !bytes.Equal(value, []byte{3}) {
t.Fatalf("database.Get Returned: 0x%x ; Expected: 0x%x", value, []byte{3})
}
}

View File

@ -9,6 +9,7 @@ import (
"github.com/ava-labs/gecko/api" "github.com/ava-labs/gecko/api"
"github.com/ava-labs/gecko/api/keystore" "github.com/ava-labs/gecko/api/keystore"
"github.com/ava-labs/gecko/chains/atomic"
"github.com/ava-labs/gecko/database" "github.com/ava-labs/gecko/database"
"github.com/ava-labs/gecko/database/prefixdb" "github.com/ava-labs/gecko/database/prefixdb"
"github.com/ava-labs/gecko/ids" "github.com/ava-labs/gecko/ids"
@ -26,6 +27,7 @@ import (
"github.com/ava-labs/gecko/snow/triggers" "github.com/ava-labs/gecko/snow/triggers"
"github.com/ava-labs/gecko/snow/validators" "github.com/ava-labs/gecko/snow/validators"
"github.com/ava-labs/gecko/utils/logging" "github.com/ava-labs/gecko/utils/logging"
"github.com/ava-labs/gecko/utils/math"
"github.com/ava-labs/gecko/vms" "github.com/ava-labs/gecko/vms"
avacon "github.com/ava-labs/gecko/snow/consensus/avalanche" avacon "github.com/ava-labs/gecko/snow/consensus/avalanche"
@ -92,6 +94,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
@ -109,6 +112,7 @@ type manager struct {
awaiter Awaiter // Waits for required connections before running bootstrapping awaiter Awaiter // Waits for required connections before running bootstrapping
server *api.Server // Handles HTTP API calls server *api.Server // Handles HTTP API calls
keystore *keystore.Keystore keystore *keystore.Keystore
sharedMemory *atomic.SharedMemory
unblocked bool unblocked bool
blockedChains []ChainParameters blockedChains []ChainParameters
@ -120,6 +124,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,
@ -135,6 +140,7 @@ func New(
awaiter Awaiter, awaiter Awaiter,
server *api.Server, server *api.Server,
keystore *keystore.Keystore, keystore *keystore.Keystore,
sharedMemory *atomic.SharedMemory,
) Manager { ) Manager {
timeoutManager := timeout.Manager{} timeoutManager := timeout.Manager{}
timeoutManager.Initialize(requestTimeout) timeoutManager.Initialize(requestTimeout)
@ -143,6 +149,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,
@ -159,6 +166,7 @@ func New(
awaiter: awaiter, awaiter: awaiter,
server: server, server: server,
keystore: keystore, keystore: keystore,
sharedMemory: sharedMemory,
} }
m.Initialize() m.Initialize()
return m return m
@ -246,6 +254,7 @@ func (m *manager) ForceCreateChain(chain ChainParameters) {
NodeID: m.nodeID, NodeID: m.nodeID,
HTTP: m.server, HTTP: m.server,
Keystore: m.keystore.NewBlockchainKeyStore(chain.ID), Keystore: m.keystore.NewBlockchainKeyStore(chain.ID),
SharedMemory: m.sharedMemory.NewBlockchainSharedMemory(chain.ID),
BCLookup: m, BCLookup: m,
} }
consensusParams := m.consensusParams consensusParams := m.consensusParams
@ -256,7 +265,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
@ -353,7 +368,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
@ -376,13 +391,22 @@ func (m *manager) createAvalancheChain(
}, },
} }
bootstrapWeight := uint64(0)
for _, beacon := range beacons.List() {
newWeight, err := math.Add64(bootstrapWeight, beacon.Weight())
if err != nil {
return err
}
bootstrapWeight = newWeight
}
engine.Initialize(avaeng.Config{ engine.Initialize(avaeng.Config{
BootstrapConfig: avaeng.BootstrapConfig{ BootstrapConfig: avaeng.BootstrapConfig{
Config: common.Config{ Config: common.Config{
Context: ctx, Context: ctx,
Validators: validators, Validators: validators,
Beacons: beacons, Beacons: beacons,
Alpha: (beacons.Len() + 1) / 2, Alpha: bootstrapWeight/2 + 1, // must be > 50%
Sender: &sender, Sender: &sender,
}, },
VtxBlocked: vtxBlocker, VtxBlocked: vtxBlocker,
@ -403,6 +427,8 @@ func (m *manager) createAvalancheChain(
go ctx.Log.RecoverAndPanic(handler.Dispatch) go ctx.Log.RecoverAndPanic(handler.Dispatch)
awaiting := &networking.AwaitingConnections{ awaiting := &networking.AwaitingConnections{
Requested: beacons,
WeightRequired: (3*bootstrapWeight + 3) / 4, // 75% must be connected to
Finish: func() { Finish: func() {
ctx.Lock.Lock() ctx.Lock.Lock()
defer ctx.Lock.Unlock() defer ctx.Lock.Unlock()
@ -410,10 +436,6 @@ func (m *manager) createAvalancheChain(
engine.Startup() engine.Startup()
}, },
} }
for _, vdr := range beacons.List() {
awaiting.Requested.Add(vdr.ID())
}
awaiting.NumRequired = (3*awaiting.Requested.Len() + 3) / 4 // 75% must be connected to
m.awaiter.AwaitConnections(awaiting) m.awaiter.AwaitConnections(awaiting)
return nil return nil
@ -454,6 +476,15 @@ func (m *manager) createSnowmanChain(
sender := sender.Sender{} sender := sender.Sender{}
sender.Initialize(ctx, m.sender, m.chainRouter, m.timeoutManager) sender.Initialize(ctx, m.sender, m.chainRouter, m.timeoutManager)
bootstrapWeight := uint64(0)
for _, beacon := range beacons.List() {
newWeight, err := math.Add64(bootstrapWeight, beacon.Weight())
if err != nil {
return err
}
bootstrapWeight = newWeight
}
// The engine handles consensus // The engine handles consensus
engine := smeng.Transitive{} engine := smeng.Transitive{}
engine.Initialize(smeng.Config{ engine.Initialize(smeng.Config{
@ -462,7 +493,7 @@ func (m *manager) createSnowmanChain(
Context: ctx, Context: ctx,
Validators: validators, Validators: validators,
Beacons: beacons, Beacons: beacons,
Alpha: (beacons.Len() + 1) / 2, Alpha: bootstrapWeight/2 + 1, // must be > 50%
Sender: &sender, Sender: &sender,
}, },
Blocked: blocked, Blocked: blocked,
@ -482,6 +513,8 @@ func (m *manager) createSnowmanChain(
go ctx.Log.RecoverAndPanic(handler.Dispatch) go ctx.Log.RecoverAndPanic(handler.Dispatch)
awaiting := &networking.AwaitingConnections{ awaiting := &networking.AwaitingConnections{
Requested: beacons,
WeightRequired: (3*bootstrapWeight + 3) / 4, // 75% must be connected to
Finish: func() { Finish: func() {
ctx.Lock.Lock() ctx.Lock.Lock()
defer ctx.Lock.Unlock() defer ctx.Lock.Unlock()
@ -489,10 +522,6 @@ func (m *manager) createSnowmanChain(
engine.Startup() engine.Startup()
}, },
} }
for _, vdr := range beacons.List() {
awaiting.Requested.Add(vdr.ID())
}
awaiting.NumRequired = (3*awaiting.Requested.Len() + 3) / 4 // 75% must be connected to
m.awaiter.AwaitConnections(awaiting) m.awaiter.AwaitConnections(awaiting)
return nil return nil
} }

37
chains/mock_manager.go Normal file
View File

@ -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() {}

View File

@ -23,6 +23,11 @@ type Batch interface {
// Replay replays the batch contents. // Replay replays the batch contents.
Replay(w KeyValueWriter) error Replay(w KeyValueWriter) error
// Inner returns a Batch writing to the inner database, if one exists. If
// this batch is already writing to the base DB, then itself should be
// returned.
Inner() Batch
} }
// Batcher wraps the NewBatch method of a backing data store. // Batcher wraps the NewBatch method of a backing data store.

View File

@ -184,6 +184,9 @@ func (b *batch) Replay(w database.KeyValueWriter) error {
return updateError(replay.err) return updateError(replay.err)
} }
// Inner returns itself
func (b *batch) Inner() database.Batch { return b }
type replayer struct { type replayer struct {
writer database.KeyValueWriter writer database.KeyValueWriter
err error err error

View File

@ -208,6 +208,9 @@ func (b *batch) Replay(w database.KeyValueWriter) error {
return nil return nil
} }
// Inner returns itself
func (b *batch) Inner() database.Batch { return b }
type iterator struct { type iterator struct {
initialized bool initialized bool
keys []string keys []string

View File

@ -69,6 +69,9 @@ func (*Batch) Reset() {}
// Replay does nothing // Replay does nothing
func (*Batch) Replay(database.KeyValueWriter) error { return database.ErrClosed } func (*Batch) Replay(database.KeyValueWriter) error { return database.ErrClosed }
// Inner returns itself
func (b *Batch) Inner() database.Batch { return b }
// Iterator does nothing // Iterator does nothing
type Iterator struct{ Err error } type Iterator struct{ Err error }

View File

@ -17,6 +17,7 @@ var (
TestBatchDelete, TestBatchDelete,
TestBatchReset, TestBatchReset,
TestBatchReplay, TestBatchReplay,
TestBatchInner,
TestIterator, TestIterator,
TestIteratorStart, TestIteratorStart,
TestIteratorPrefix, TestIteratorPrefix,
@ -299,6 +300,62 @@ func TestBatchReplay(t *testing.T, db Database) {
} }
} }
// TestBatchInner ...
func TestBatchInner(t *testing.T, db Database) {
key1 := []byte("hello1")
value1 := []byte("world1")
key2 := []byte("hello2")
value2 := []byte("world2")
firstBatch := db.NewBatch()
if firstBatch == nil {
t.Fatalf("db.NewBatch returned nil")
}
if err := firstBatch.Put(key1, value1); err != nil {
t.Fatalf("Unexpected error on batch.Put: %s", err)
}
secondBatch := db.NewBatch()
if secondBatch == nil {
t.Fatalf("db.NewBatch returned nil")
}
if err := secondBatch.Put(key2, value2); err != nil {
t.Fatalf("Unexpected error on batch.Put: %s", err)
}
innerFirstBatch := firstBatch.Inner()
innerSecondBatch := secondBatch.Inner()
if err := innerFirstBatch.Replay(innerSecondBatch); err != nil {
t.Fatalf("Unexpected error on batch.Replay: %s", err)
}
if err := innerSecondBatch.Write(); err != nil {
t.Fatalf("Unexpected error on batch.Write: %s", err)
}
if has, err := db.Has(key1); err != nil {
t.Fatalf("Unexpected error on db.Has: %s", err)
} else if !has {
t.Fatalf("db.Has unexpectedly returned false on key %s", key1)
} else if v, err := db.Get(key1); err != nil {
t.Fatalf("Unexpected error on db.Get: %s", err)
} else if !bytes.Equal(value1, v) {
t.Fatalf("db.Get: Returned: 0x%x ; Expected: 0x%x", v, value1)
} else if has, err := db.Has(key2); err != nil {
t.Fatalf("Unexpected error on db.Has: %s", err)
} else if !has {
t.Fatalf("db.Has unexpectedly returned false on key %s", key2)
} else if v, err := db.Get(key2); err != nil {
t.Fatalf("Unexpected error on db.Get: %s", err)
} else if !bytes.Equal(value2, v) {
t.Fatalf("db.Get: Returned: 0x%x ; Expected: 0x%x", v, value2)
}
}
// TestIterator ... // TestIterator ...
func TestIterator(t *testing.T, db Database) { func TestIterator(t *testing.T, db Database) {
key1 := []byte("hello1") key1 := []byte("hello1")

View File

@ -184,29 +184,55 @@ func (db *Database) Commit() error {
db.lock.Lock() db.lock.Lock()
defer db.lock.Unlock() defer db.lock.Unlock()
if db.mem == nil { batch, err := db.commitBatch()
return database.ErrClosed if err != nil {
return err
} }
if len(db.mem) == 0 { if err := batch.Write(); err != nil {
return nil return err
}
db.abort()
return nil
}
// Abort all changes to the underlying database
func (db *Database) Abort() {
db.lock.Lock()
defer db.lock.Unlock()
db.abort()
}
func (db *Database) abort() { db.mem = make(map[string]valueDelete, memdb.DefaultSize) }
// CommitBatch returns a batch that will commit all pending writes to the underlying database
func (db *Database) CommitBatch() (database.Batch, error) {
db.lock.Lock()
defer db.lock.Unlock()
return db.commitBatch()
}
func (db *Database) commitBatch() (database.Batch, error) {
if db.mem == nil {
return nil, database.ErrClosed
} }
batch := db.db.NewBatch() batch := db.db.NewBatch()
for key, value := range db.mem { for key, value := range db.mem {
if value.delete { if value.delete {
if err := batch.Delete([]byte(key)); err != nil { if err := batch.Delete([]byte(key)); err != nil {
return err return nil, err
} }
} else if err := batch.Put([]byte(key), value.value); err != nil { } else if err := batch.Put([]byte(key), value.value); err != nil {
return err return nil, err
} }
} }
if err := batch.Write(); err != nil { if err := batch.Write(); err != nil {
return err return nil, err
} }
db.mem = make(map[string]valueDelete, memdb.DefaultSize) return batch, nil
return nil
} }
// Close implements the database.Database interface // Close implements the database.Database interface
@ -289,6 +315,9 @@ func (b *batch) Replay(w database.KeyValueWriter) error {
return nil return nil
} }
// Inner returns itself
func (b *batch) Inner() database.Batch { return b }
// iterator walks over both the in memory database and the underlying database // iterator walks over both the in memory database and the underlying database
// at the same time. // at the same time.
type iterator struct { type iterator struct {

View File

@ -256,6 +256,72 @@ func TestCommitClosedDelete(t *testing.T) {
} }
} }
func TestAbort(t *testing.T) {
baseDB := memdb.New()
db := New(baseDB)
key1 := []byte("hello1")
value1 := []byte("world1")
if err := db.Put(key1, value1); err != nil {
t.Fatalf("Unexpected error on db.Put: %s", err)
}
if value, err := db.Get(key1); err != nil {
t.Fatalf("Unexpected error on db.Get: %s", err)
} else if !bytes.Equal(value, value1) {
t.Fatalf("db.Get Returned: 0x%x ; Expected: 0x%x", value, value1)
} else if has, err := baseDB.Has(key1); err != nil {
t.Fatalf("Unexpected error on db.Has: %s", err)
} else if has {
t.Fatalf("db.Has Returned: %v ; Expected: %v", has, false)
}
db.Abort()
if has, err := db.Has(key1); err != nil {
t.Fatalf("Unexpected error on db.Has: %s", err)
} else if has {
t.Fatalf("db.Has Returned: %v ; Expected: %v", has, false)
} else if has, err := baseDB.Has(key1); err != nil {
t.Fatalf("Unexpected error on db.Has: %s", err)
} else if has {
t.Fatalf("db.Has Returned: %v ; Expected: %v", has, false)
}
}
func TestCommitBatch(t *testing.T) {
baseDB := memdb.New()
db := New(baseDB)
key1 := []byte("hello1")
value1 := []byte("world1")
if err := db.Put(key1, value1); err != nil {
t.Fatalf("Unexpected error on db.Put: %s", err)
}
batch, err := db.CommitBatch()
if err != nil {
t.Fatalf("Unexpected error on db.CommitBatch: %s", err)
}
db.Abort()
if err := batch.Write(); err != nil {
t.Fatalf("Unexpected error on batch.Write: %s", err)
}
if value, err := db.Get(key1); err != nil {
t.Fatalf("Unexpected error on db.Get: %s", err)
} else if !bytes.Equal(value, value1) {
t.Fatalf("db.Get Returned: 0x%x ; Expected: 0x%x", value, value1)
} else if value, err := baseDB.Get(key1); err != nil {
t.Fatalf("Unexpected error on db.Get: %s", err)
} else if !bytes.Equal(value, value1) {
t.Fatalf("db.Get Returned: 0x%x ; Expected: 0x%x", value, value1)
}
}
func TestSetDatabase(t *testing.T) { func TestSetDatabase(t *testing.T) {
baseDB := memdb.New() baseDB := memdb.New()
newDB := memdb.New() newDB := memdb.New()

78
genesis/aliases.go Normal file
View File

@ -0,0 +1,78 @@
// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package genesis
import (
"github.com/ava-labs/gecko/ids"
"github.com/ava-labs/gecko/vms/avm"
"github.com/ava-labs/gecko/vms/evm"
"github.com/ava-labs/gecko/vms/nftfx"
"github.com/ava-labs/gecko/vms/platformvm"
"github.com/ava-labs/gecko/vms/propertyfx"
"github.com/ava-labs/gecko/vms/secp256k1fx"
"github.com/ava-labs/gecko/vms/spchainvm"
"github.com/ava-labs/gecko/vms/spdagvm"
"github.com/ava-labs/gecko/vms/timestampvm"
)
// Aliases returns the default aliases based on the network ID
func Aliases(networkID uint32) (map[string][]string, map[[32]byte][]string, map[[32]byte][]string, error) {
generalAliases := map[string][]string{
"vm/" + platformvm.ID.String(): []string{"vm/platform"},
"vm/" + avm.ID.String(): []string{"vm/avm"},
"vm/" + evm.ID.String(): []string{"vm/evm"},
"vm/" + spdagvm.ID.String(): []string{"vm/spdag"},
"vm/" + spchainvm.ID.String(): []string{"vm/spchain"},
"vm/" + timestampvm.ID.String(): []string{"vm/timestamp"},
"bc/" + ids.Empty.String(): []string{"P", "platform", "bc/P", "bc/platform"},
}
chainAliases := map[[32]byte][]string{
ids.Empty.Key(): []string{"P", "platform"},
}
vmAliases := map[[32]byte][]string{
platformvm.ID.Key(): []string{"platform"},
avm.ID.Key(): []string{"avm"},
evm.ID.Key(): []string{"evm"},
spdagvm.ID.Key(): []string{"spdag"},
spchainvm.ID.Key(): []string{"spchain"},
timestampvm.ID.Key(): []string{"timestamp"},
secp256k1fx.ID.Key(): []string{"secp256k1fx"},
nftfx.ID.Key(): []string{"nftfx"},
propertyfx.ID.Key(): []string{"propertyfx"},
}
genesisBytes, err := Genesis(networkID)
if err != nil {
return nil, nil, nil, err
}
genesis := &platformvm.Genesis{} // TODO let's not re-create genesis to do aliasing
if err := platformvm.Codec.Unmarshal(genesisBytes, genesis); err != nil {
return nil, nil, nil, err
}
if err := genesis.Initialize(); err != nil {
return nil, nil, nil, err
}
for _, chain := range genesis.Chains {
switch {
case avm.ID.Equals(chain.VMID):
generalAliases["bc/"+chain.ID().String()] = []string{"X", "avm", "bc/X", "bc/avm"}
chainAliases[chain.ID().Key()] = []string{"X", "avm"}
case evm.ID.Equals(chain.VMID):
generalAliases["bc/"+chain.ID().String()] = []string{"C", "evm", "bc/C", "bc/evm"}
chainAliases[chain.ID().Key()] = []string{"C", "evm"}
case spdagvm.ID.Equals(chain.VMID):
generalAliases["bc/"+chain.ID().String()] = []string{"bc/spdag"}
chainAliases[chain.ID().Key()] = []string{"spdag"}
case spchainvm.ID.Equals(chain.VMID):
generalAliases["bc/"+chain.ID().String()] = []string{"bc/spchain"}
chainAliases[chain.ID().Key()] = []string{"spchain"}
case timestampvm.ID.Equals(chain.VMID):
generalAliases["bc/"+chain.ID().String()] = []string{"bc/timestamp"}
chainAliases[chain.ID().Key()] = []string{"timestamp"}
}
}
return generalAliases, chainAliases, vmAliases, nil
}

108
genesis/config.go Normal file
View File

@ -0,0 +1,108 @@
// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package genesis
import (
"github.com/ava-labs/gecko/ids"
"github.com/ava-labs/gecko/vms/evm"
)
// Note that since an AVA network has exactly one Platform Chain,
// and the Platform Chain defines the genesis state of the network
// (who is staking, which chains exist, etc.), defining the genesis
// state of the Platform Chain is the same as defining the genesis
// state of the network.
// Config contains the genesis addresses used to construct a genesis
type Config struct {
MintAddresses, FundedAddresses, FundedEVMAddresses, StakerIDs []string
ParsedMintAddresses, ParsedFundedAddresses, ParsedStakerIDs []ids.ShortID
}
func (c *Config) init() error {
c.ParsedMintAddresses = nil
for _, addrStr := range c.MintAddresses {
addr, err := ids.ShortFromString(addrStr)
if err != nil {
return err
}
c.ParsedMintAddresses = append(c.ParsedMintAddresses, addr)
}
c.ParsedFundedAddresses = nil
for _, addrStr := range c.FundedAddresses {
addr, err := ids.ShortFromString(addrStr)
if err != nil {
return err
}
c.ParsedFundedAddresses = append(c.ParsedFundedAddresses, addr)
}
c.ParsedStakerIDs = nil
for _, addrStr := range c.StakerIDs {
addr, err := ids.ShortFromString(addrStr)
if err != nil {
return err
}
c.ParsedStakerIDs = append(c.ParsedStakerIDs, addr)
}
return nil
}
// Hard coded genesis constants
var (
CascadeConfig = Config{
MintAddresses: []string{
"95YUFjhDG892VePMzpwKF9JzewGKvGRi3",
},
FundedAddresses: []string{
"9uKvvA7E35QCwLvAaohXTCfFejbf3Rv17",
"JLrYNMYXANGj43BfWXBxMMAEenUBp1Sbn",
"7TUTzwrU6nbZtWHjTHEpdneUvjKBxb3EM",
"77mPUXBdQKwQpPoX6rckCZGLGGdkuG1G6",
"4gGWdFZ4Gax1B466YKXyKRRpWLb42Afdt",
"CKTkzAPsRxCreyiDTnjGxLmjMarxF28fi",
"4ABm9gFHVtsNdcKSd1xsacFkGneSgzpaa",
"DpL8PTsrjtLzv5J8LL3D2A6YcnCTqrNH9",
"ZdhZv6oZrmXLyFDy6ovXAu6VxmbTsT2h",
"6cesTteH62Y5mLoDBUASaBvCXuL2AthL",
},
FundedEVMAddresses: []string{
"0x572f4D80f10f663B5049F789546f25f70Bb62a7F",
},
StakerIDs: []string{
"NX4zVkuiRJZYe6Nzzav7GXN3TakUet3Co",
"CMsa8cMw4eib1Hb8GG4xiUKAq5eE1BwUX",
"DsMP6jLhi1MkDVc3qx9xx9AAZWx8e87Jd",
"N86eodVZja3GEyZJTo3DFUPGpxEEvjGHs",
"EkKeGSLUbHrrtuayBtbwgWDRUiAziC3ao",
},
}
DefaultConfig = Config{
MintAddresses: []string{},
FundedAddresses: []string{
// Private key: ewoqjP7PxY4yr3iLTpLisriqt94hdyDFNgchSxGGztUrTXtNN
"6Y3kysjF9jnHnYkdS9yGAuoHyae2eNmeV",
},
FundedEVMAddresses: []string{
// Private key: evm.GenesisTestKey
evm.GenesisTestAddr,
},
StakerIDs: []string{
"7Xhw2mDxuDS44j42TCB6U5579esbSt3Lg",
"MFrZFVCXPv5iCn6M9K6XduxGTYp891xXZ",
"NFBbbJ4qCmNaCzeW7sxErhvWqvEQMnYcN",
"GWPcbFJZFfZreETSoWjPimr846mXEKCtu",
"P7oB2McjBGgW2NXXWVYjV8JEDFoW9xDE5",
},
}
)
// GetConfig ...
func GetConfig(networkID uint32) *Config {
switch networkID {
case CascadeID:
return &CascadeConfig
default:
return &DefaultConfig
}
}

View File

@ -3,511 +3,316 @@
package genesis package genesis
// TODO: Move this to a separate repo and leave only a byte array
import ( import (
"errors"
"fmt" "fmt"
"math" "math/big"
"regexp" "time"
"strconv"
"strings" "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/utils/wrappers"
"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/evm" "github.com/ava-labs/gecko/vms/evm"
"github.com/ava-labs/gecko/vms/nftfx"
"github.com/ava-labs/gecko/vms/platformvm" "github.com/ava-labs/gecko/vms/platformvm"
"github.com/ava-labs/gecko/vms/propertyfx"
"github.com/ava-labs/gecko/vms/secp256k1fx"
"github.com/ava-labs/gecko/vms/spchainvm" "github.com/ava-labs/gecko/vms/spchainvm"
"github.com/ava-labs/gecko/vms/spdagvm" "github.com/ava-labs/gecko/vms/spdagvm"
"github.com/ava-labs/gecko/vms/timestampvm" "github.com/ava-labs/gecko/vms/timestampvm"
) )
// Note that since an AVA network has exactly one Platform Chain,
// and the Platform Chain defines the genesis state of the network
// (who is staking, which chains exist, etc.), defining the genesis
// state of the Platform Chain is the same as defining the genesis
// state of the network.
// Hardcoded network IDs
const (
MainnetID uint32 = 1
TestnetID uint32 = 2
BorealisID uint32 = 2
LocalID uint32 = 12345
MainnetName = "mainnet"
TestnetName = "testnet"
BorealisName = "borealis"
LocalName = "local"
)
var (
validNetworkName = regexp.MustCompile(`network-[0-9]+`)
)
// Hard coded genesis constants
var (
// Give special names to the mainnet and testnet
NetworkIDToNetworkName = map[uint32]string{
MainnetID: MainnetName,
TestnetID: BorealisName,
LocalID: LocalName,
}
NetworkNameToNetworkID = map[string]uint32{
MainnetName: MainnetID,
TestnetName: TestnetID,
BorealisName: BorealisID,
LocalName: LocalID,
}
Keys = []string{
"ewoqjP7PxY4yr3iLTpLisriqt94hdyDFNgchSxGGztUrTXtNN",
}
Addresses = []string{
"6Y3kysjF9jnHnYkdS9yGAuoHyae2eNmeV",
}
ParsedAddresses = []ids.ShortID{}
StakerIDs = []string{
"7Xhw2mDxuDS44j42TCB6U5579esbSt3Lg",
"MFrZFVCXPv5iCn6M9K6XduxGTYp891xXZ",
"NFBbbJ4qCmNaCzeW7sxErhvWqvEQMnYcN",
"GWPcbFJZFfZreETSoWjPimr846mXEKCtu",
"P7oB2McjBGgW2NXXWVYjV8JEDFoW9xDE5",
}
ParsedStakerIDs = []ids.ShortID{}
)
func init() {
for _, addrStr := range Addresses {
addr, err := ids.ShortFromString(addrStr)
if err != nil {
panic(err)
}
ParsedAddresses = append(ParsedAddresses, addr)
}
for _, stakerIDStr := range StakerIDs {
stakerID, err := ids.ShortFromString(stakerIDStr)
if err != nil {
panic(err)
}
ParsedStakerIDs = append(ParsedStakerIDs, stakerID)
}
}
// NetworkName returns a human readable name for the network with
// ID [networkID]
func NetworkName(networkID uint32) string {
if name, exists := NetworkIDToNetworkName[networkID]; exists {
return name
}
return fmt.Sprintf("network-%d", networkID)
}
// NetworkID returns the ID of the network with name [networkName]
func NetworkID(networkName string) (uint32, error) {
networkName = strings.ToLower(networkName)
if id, exists := NetworkNameToNetworkID[networkName]; exists {
return id, nil
}
if id, err := strconv.ParseUint(networkName, 10, 0); err == nil {
if id > math.MaxUint32 {
return 0, fmt.Errorf("NetworkID %s not in [0, 2^32)", networkName)
}
return uint32(id), nil
}
if validNetworkName.MatchString(networkName) {
if id, err := strconv.Atoi(networkName[8:]); err == nil {
if id > math.MaxUint32 {
return 0, fmt.Errorf("NetworkID %s not in [0, 2^32)", networkName)
}
return uint32(id), nil
}
}
return 0, fmt.Errorf("Failed to parse %s as a network name", networkName)
}
// Aliases returns the default aliases based on the network ID
func Aliases(networkID uint32) (generalAliases map[string][]string, chainAliases map[[32]byte][]string, vmAliases map[[32]byte][]string) {
generalAliases = map[string][]string{
"vm/" + platformvm.ID.String(): []string{"vm/platform"},
"vm/" + avm.ID.String(): []string{"vm/avm"},
"vm/" + evm.ID.String(): []string{"vm/evm"},
"vm/" + spdagvm.ID.String(): []string{"vm/spdag"},
"vm/" + spchainvm.ID.String(): []string{"vm/spchain"},
"vm/" + timestampvm.ID.String(): []string{"vm/timestamp"},
"bc/" + ids.Empty.String(): []string{"P", "platform", "bc/P", "bc/platform"},
}
chainAliases = map[[32]byte][]string{
ids.Empty.Key(): []string{"P", "platform"},
}
vmAliases = map[[32]byte][]string{
platformvm.ID.Key(): []string{"platform"},
avm.ID.Key(): []string{"avm"},
evm.ID.Key(): []string{"evm"},
spdagvm.ID.Key(): []string{"spdag"},
spchainvm.ID.Key(): []string{"spchain"},
timestampvm.ID.Key(): []string{"timestamp"},
}
genesisBytes := Genesis(networkID)
genesis := &platformvm.Genesis{} // TODO let's not re-create genesis to do aliasing
platformvm.Codec.Unmarshal(genesisBytes, genesis) // TODO check for error
genesis.Initialize()
for _, chain := range genesis.Chains {
switch {
case avm.ID.Equals(chain.VMID):
generalAliases["bc/"+chain.ID().String()] = []string{"X", "avm", "bc/X", "bc/avm"}
chainAliases[chain.ID().Key()] = []string{"X", "avm"}
case evm.ID.Equals(chain.VMID):
generalAliases["bc/"+chain.ID().String()] = []string{"C", "evm", "bc/C", "bc/evm"}
chainAliases[chain.ID().Key()] = []string{"C", "evm"}
case spdagvm.ID.Equals(chain.VMID):
generalAliases["bc/"+chain.ID().String()] = []string{"bc/spdag"}
chainAliases[chain.ID().Key()] = []string{"spdag"}
case spchainvm.ID.Equals(chain.VMID):
generalAliases["bc/"+chain.ID().String()] = []string{"bc/spchain"}
chainAliases[chain.ID().Key()] = []string{"spchain"}
case timestampvm.ID.Equals(chain.VMID):
generalAliases["bc/"+chain.ID().String()] = []string{"bc/timestamp"}
chainAliases[chain.ID().Key()] = []string{"timestamp"}
}
}
return
}
// Genesis returns the genesis data of the Platform Chain. // Genesis returns the genesis data of the Platform Chain.
// Since the Platform Chain causes the creation of all other // Since an AVA network has exactly one Platform Chain, and the Platform Chain
// chains, this function returns the genesis data of the entire network. // defines the genesis state of the network (who is staking, which chains exist,
// etc.), defining the genesis state of the Platform Chain is the same as
// defining the genesis state of the network.
// The ID of the new network is [networkID]. // The ID of the new network is [networkID].
func Genesis(networkID uint32) []byte {
if networkID != LocalID { // FromConfig ...
panic("unknown network ID provided") func FromConfig(networkID uint32, config *Config) ([]byte, error) {
if err := config.init(); err != nil {
return nil, err
} }
return []byte{ // Specify the genesis state of the AVM
0x00, 0x00, 0x00, 0x01, 0x3c, 0xb7, 0xd3, 0x84, avmArgs := avm.BuildGenesisArgs{}
0x2e, 0x8c, 0xee, 0x6a, 0x0e, 0xbd, 0x09, 0xf1, {
0xfe, 0x88, 0x4f, 0x68, 0x61, 0xe1, 0xb2, 0x9c, ava := avm.AssetDefinition{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, Name: "AVA",
0x00, 0x00, 0x12, 0x30, 0x9c, 0xe5, 0x40, 0x00, Symbol: "AVA",
0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, Denomination: 9,
0x05, 0xde, 0x31, 0xb4, 0xd8, 0xb2, 0x29, 0x91, InitialState: map[string][]interface{}{},
0xd5, 0x1a, 0xa6, 0xaa, 0x1f, 0xc7, 0x33, 0xf2, }
0x3a, 0x85, 0x1a, 0x8c, 0x94, 0x00, 0x00, 0x12,
0x30, 0x9c, 0xe5, 0x40, 0x00, 0x00, 0x00, 0x00, if len(config.MintAddresses) > 0 {
0x00, 0x5d, 0xbb, 0x75, 0x80, 0x00, 0x00, 0x00, ava.InitialState["variableCap"] = []interface{}{avm.Owners{
0x00, 0x5f, 0x9c, 0xa9, 0x00, 0x00, 0x00, 0x30, Threshold: 1,
0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, Minters: config.MintAddresses,
0x00, 0x3c, 0xb7, 0xd3, 0x84, 0x2e, 0x8c, 0xee, }}
0x6a, 0x0e, 0xbd, 0x09, 0xf1, 0xfe, 0x88, 0x4f, }
0x68, 0x61, 0xe1, 0xb2, 0x9c, 0x00, 0x00, 0x00, for _, addr := range config.FundedAddresses {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ava.InitialState["fixedCap"] = append(ava.InitialState["fixedCap"], avm.Holder{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, Amount: json.Uint64(45 * units.MegaAva),
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, Address: addr,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, })
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, avmArgs.GenesisData = map[string]avm.AssetDefinition{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // The AVM starts out with one asset, $AVA
0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0xaa, 0x18, "AVA": ava,
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, 0x05, 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, 0x05,
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, 0x05, 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, 0x04, 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,
} }
avmReply := avm.BuildGenesisReply{}
avmSS := avm.StaticService{}
err := avmSS.BuildGenesis(nil, &avmArgs, &avmReply)
if err != nil {
panic(err)
}
// Specify the genesis state of Athereum (the built-in instance of the EVM)
evmBalance, success := new(big.Int).SetString("33b2e3c9fd0804000000000", 16)
if success != true {
return nil, errors.New("problem creating evm genesis state")
}
alloc := core.GenesisAlloc{}
for _, addr := range config.FundedEVMAddresses {
alloc[common.HexToAddress(addr)] = core.GenesisAccount{
Balance: evmBalance,
}
}
evmArgs := core.Genesis{
Config: &params.ChainConfig{
ChainID: big.NewInt(43110),
HomesteadBlock: big.NewInt(0),
DAOForkBlock: big.NewInt(0),
DAOForkSupport: true,
EIP150Block: big.NewInt(0),
EIP150Hash: common.HexToHash("0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0"),
EIP155Block: big.NewInt(0),
EIP158Block: big.NewInt(0),
ByzantiumBlock: big.NewInt(0),
ConstantinopleBlock: big.NewInt(0),
PetersburgBlock: big.NewInt(0),
},
Nonce: 0,
Timestamp: 0,
ExtraData: []byte{0},
GasLimit: 100000000,
Difficulty: big.NewInt(0),
Mixhash: common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"),
Coinbase: common.HexToAddress("0x0000000000000000000000000000000000000000"),
Alloc: alloc,
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 config.ParsedFundedAddresses {
spdagvmArgs.Outputs = append(spdagvmArgs.Outputs,
spdagvm.APIOutput{
Amount: json.Uint64(20 * units.KiloAva),
Threshold: 1,
Addresses: []ids.ShortID{addr},
},
)
}
spdagvmReply := spdagvm.BuildGenesisReply{}
spdagvmSS := spdagvm.StaticService{}
if err := spdagvmSS.BuildGenesis(nil, &spdagvmArgs, &spdagvmReply); err != nil {
return nil, fmt.Errorf("problem creating simple payments DAG: %w", err)
}
// Specify the genesis state of the simple payments chain
spchainvmArgs := spchainvm.BuildGenesisArgs{}
for _, addr := range config.ParsedFundedAddresses {
spchainvmArgs.Accounts = append(spchainvmArgs.Accounts,
spchainvm.APIAccount{
Address: addr,
Balance: json.Uint64(20 * units.KiloAva),
},
)
}
spchainvmReply := spchainvm.BuildGenesisReply{}
spchainvmSS := spchainvm.StaticService{}
if err := spchainvmSS.BuildGenesis(nil, &spchainvmArgs, &spchainvmReply); err != nil {
return nil, fmt.Errorf("problem creating simple payments chain: %w", err)
}
// Specify the initial state of the Platform Chain
platformvmArgs := platformvm.BuildGenesisArgs{
NetworkID: json.Uint32(networkID),
}
for _, addr := range config.ParsedFundedAddresses {
platformvmArgs.Accounts = append(platformvmArgs.Accounts,
platformvm.APIAccount{
Address: addr,
Balance: json.Uint64(20 * units.KiloAva),
},
)
}
genesisTime := time.Date(
/*year=*/ 2019,
/*month=*/ time.November,
/*day=*/ 1,
/*hour=*/ 0,
/*minute=*/ 0,
/*second=*/ 0,
/*nano-second=*/ 0,
/*location=*/ time.UTC,
)
stakingDuration := 365 * 24 * time.Hour // ~ 1 year
endStakingTime := genesisTime.Add(stakingDuration)
for i, validatorID := range config.ParsedStakerIDs {
weight := json.Uint64(20 * units.KiloAva)
platformvmArgs.Validators = append(platformvmArgs.Validators,
platformvm.APIDefaultSubnetValidator{
APIValidator: platformvm.APIValidator{
StartTime: json.Uint64(genesisTime.Unix()),
EndTime: json.Uint64(endStakingTime.Unix()),
Weight: &weight,
ID: validatorID,
},
Destination: config.ParsedFundedAddresses[i%len(config.ParsedFundedAddresses)],
},
)
}
// Specify the chains that exist upon this network's creation
platformvmArgs.Chains = []platformvm.APIChain{
platformvm.APIChain{
GenesisData: avmReply.Bytes,
SubnetID: platformvm.DefaultSubnetID,
VMID: avm.ID,
FxIDs: []ids.ID{
secp256k1fx.ID,
nftfx.ID,
propertyfx.ID,
},
Name: "X-Chain",
},
platformvm.APIChain{
GenesisData: 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
} }
// Genesis ...
func Genesis(networkID uint32) ([]byte, error) { return FromConfig(networkID, GetConfig(networkID)) }
// VMGenesis ... // VMGenesis ...
func VMGenesis(networkID uint32, vmID ids.ID) *platformvm.CreateChainTx { func VMGenesis(networkID uint32, vmID ids.ID) (*platformvm.CreateChainTx, error) {
genesisBytes := Genesis(networkID) genesisBytes, err := Genesis(networkID)
if err != nil {
return nil, err
}
genesis := platformvm.Genesis{} genesis := platformvm.Genesis{}
platformvm.Codec.Unmarshal(genesisBytes, &genesis) platformvm.Codec.Unmarshal(genesisBytes, &genesis)
if err := genesis.Initialize(); err != nil {
return nil, err
}
for _, chain := range genesis.Chains { for _, chain := range genesis.Chains {
if chain.VMID.Equals(vmID) { if chain.VMID.Equals(vmID) {
return chain return chain, nil
} }
} }
return nil return nil, fmt.Errorf("couldn't find subnet with VM ID %s", vmID)
}
// AVAAssetID ...
func AVAAssetID(networkID uint32) (ids.ID, error) {
createAVM, err := VMGenesis(networkID, avm.ID)
if err != nil {
return ids.ID{}, err
}
c := codec.NewDefault()
errs := wrappers.Errs{}
errs.Add(
c.RegisterType(&avm.BaseTx{}),
c.RegisterType(&avm.CreateAssetTx{}),
c.RegisterType(&avm.OperationTx{}),
c.RegisterType(&avm.ImportTx{}),
c.RegisterType(&avm.ExportTx{}),
c.RegisterType(&secp256k1fx.TransferInput{}),
c.RegisterType(&secp256k1fx.MintOutput{}),
c.RegisterType(&secp256k1fx.TransferOutput{}),
c.RegisterType(&secp256k1fx.MintOperation{}),
c.RegisterType(&secp256k1fx.Credential{}),
)
if errs.Errored() {
return ids.ID{}, errs.Err
}
genesis := avm.Genesis{}
if err := c.Unmarshal(createAVM.GenesisData, &genesis); err != nil {
return ids.ID{}, err
}
if len(genesis.Txs) == 0 {
return ids.ID{}, errors.New("genesis creates no transactions")
}
genesisTx := genesis.Txs[0]
tx := avm.Tx{UnsignedTx: &genesisTx.CreateAssetTx}
txBytes, err := c.Marshal(&tx)
if err != nil {
return ids.ID{}, err
}
tx.Initialize(txBytes)
return tx.ID(), nil
} }

View File

@ -6,6 +6,7 @@ package genesis
import ( import (
"testing" "testing"
"github.com/ava-labs/gecko/ids"
"github.com/ava-labs/gecko/vms/avm" "github.com/ava-labs/gecko/vms/avm"
"github.com/ava-labs/gecko/vms/evm" "github.com/ava-labs/gecko/vms/evm"
"github.com/ava-labs/gecko/vms/platformvm" "github.com/ava-labs/gecko/vms/platformvm"
@ -17,11 +18,11 @@ func TestNetworkName(t *testing.T) {
if name := NetworkName(MainnetID); name != MainnetName { if name := NetworkName(MainnetID); name != MainnetName {
t.Fatalf("NetworkID was incorrectly named. Result: %s ; Expected: %s", name, MainnetName) t.Fatalf("NetworkID was incorrectly named. Result: %s ; Expected: %s", name, MainnetName)
} }
if name := NetworkName(TestnetID); name != BorealisName { if name := NetworkName(TestnetID); name != CascadeName {
t.Fatalf("NetworkID was incorrectly named. Result: %s ; Expected: %s", name, BorealisName) t.Fatalf("NetworkID was incorrectly named. Result: %s ; Expected: %s", name, CascadeName)
} }
if name := NetworkName(BorealisID); name != BorealisName { if name := NetworkName(CascadeID); name != CascadeName {
t.Fatalf("NetworkID was incorrectly named. Result: %s ; Expected: %s", name, BorealisName) t.Fatalf("NetworkID was incorrectly named. Result: %s ; Expected: %s", name, CascadeName)
} }
if name := NetworkName(4294967295); name != "network-4294967295" { if name := NetworkName(4294967295); name != "network-4294967295" {
t.Fatalf("NetworkID was incorrectly named. Result: %s ; Expected: %s", name, "network-4294967295") t.Fatalf("NetworkID was incorrectly named. Result: %s ; Expected: %s", name, "network-4294967295")
@ -45,7 +46,7 @@ func TestNetworkID(t *testing.T) {
t.Fatalf("Returned wrong network. Expected: %d ; Returned %d", TestnetID, id) t.Fatalf("Returned wrong network. Expected: %d ; Returned %d", TestnetID, id)
} }
id, err = NetworkID(BorealisName) id, err = NetworkID(CascadeName)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -53,7 +54,7 @@ func TestNetworkID(t *testing.T) {
t.Fatalf("Returned wrong network. Expected: %d ; Returned %d", TestnetID, id) t.Fatalf("Returned wrong network. Expected: %d ; Returned %d", TestnetID, id)
} }
id, err = NetworkID("bOrEaLiS") id, err = NetworkID("cAsCaDe")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -91,7 +92,7 @@ func TestNetworkID(t *testing.T) {
} }
func TestAliases(t *testing.T) { func TestAliases(t *testing.T) {
generalAliases, _, _ := Aliases(LocalID) generalAliases, _, _, _ := Aliases(LocalID)
if _, exists := generalAliases["vm/"+platformvm.ID.String()]; !exists { if _, exists := generalAliases["vm/"+platformvm.ID.String()]; !exists {
t.Fatalf("Should have a custom alias from the vm") t.Fatalf("Should have a custom alias from the vm")
} else if _, exists := generalAliases["vm/"+avm.ID.String()]; !exists { } else if _, exists := generalAliases["vm/"+avm.ID.String()]; !exists {
@ -106,9 +107,84 @@ func TestAliases(t *testing.T) {
} }
func TestGenesis(t *testing.T) { func TestGenesis(t *testing.T) {
genesisBytes := Genesis(LocalID) genesisBytes, err := Genesis(LocalID)
if err != nil {
t.Fatal(err)
}
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)
} }
} }
func TestVMGenesis(t *testing.T) {
tests := []struct {
networkID uint32
vmID ids.ID
expectedID string
}{
{
networkID: CascadeID,
vmID: avm.ID,
expectedID: "4ktRjsAKxgMr2aEzv9SWmrU7Xk5FniHUrVCX4P1TZSfTLZWFM",
},
{
networkID: LocalID,
vmID: avm.ID,
expectedID: "4R5p2RXDGLqaifZE4hHWH9owe34pfoBULn1DrQTWivjg8o4aH",
},
{
networkID: CascadeID,
vmID: evm.ID,
expectedID: "2mUYSXfLrDtigwbzj1LxKVsHwELghc5sisoXrzJwLqAAQHF4i",
},
{
networkID: LocalID,
vmID: evm.ID,
expectedID: "tZGm6RCkeGpVETUTp11DW3UYFZmm69zfqxchpHrSF7wgy8rmw",
},
}
for _, test := range tests {
genesisTx, err := VMGenesis(test.networkID, test.vmID)
if err != nil {
t.Fatal(err)
}
if result := genesisTx.ID().String(); test.expectedID != result {
t.Fatalf("%s genesisID with networkID %d was expected to be %s but was %s",
test.vmID,
test.networkID,
test.expectedID,
result)
}
}
}
func TestAVAAssetID(t *testing.T) {
tests := []struct {
networkID uint32
expectedID string
}{
{
networkID: CascadeID,
expectedID: "21d7KVtPrubc5fHr6CGNcgbUb4seUjmZKr35ZX7BZb5iP8pXWA",
},
{
networkID: LocalID,
expectedID: "n8XH5JY1EX5VYqDeAhB4Zd4GKxi9UNQy6oPpMsCAj1Q6xkiiL",
},
}
for _, test := range tests {
avaID, err := AVAAssetID(test.networkID)
if err != nil {
t.Fatal(err)
}
if result := avaID.String(); test.expectedID != result {
t.Fatalf("AVA assetID with networkID %d was expected to be %s but was %s",
test.networkID,
test.expectedID,
result)
}
}
}

73
genesis/network_id.go Normal file
View File

@ -0,0 +1,73 @@
// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package genesis
import (
"fmt"
"math"
"regexp"
"strconv"
"strings"
)
// Hardcoded network IDs
var (
MainnetID uint32 = 1
TestnetID uint32 = 2
CascadeID uint32 = 2
LocalID uint32 = 12345
MainnetName = "mainnet"
TestnetName = "testnet"
CascadeName = "cascade"
LocalName = "local"
NetworkIDToNetworkName = map[uint32]string{
MainnetID: MainnetName,
TestnetID: CascadeName,
LocalID: LocalName,
}
NetworkNameToNetworkID = map[string]uint32{
MainnetName: MainnetID,
TestnetName: TestnetID,
CascadeName: CascadeID,
LocalName: LocalID,
}
validNetworkName = regexp.MustCompile(`network-[0-9]+`)
)
// NetworkName returns a human readable name for the network with
// ID [networkID]
func NetworkName(networkID uint32) string {
if name, exists := NetworkIDToNetworkName[networkID]; exists {
return name
}
return fmt.Sprintf("network-%d", networkID)
}
// NetworkID returns the ID of the network with name [networkName]
func NetworkID(networkName string) (uint32, error) {
networkName = strings.ToLower(networkName)
if id, exists := NetworkNameToNetworkID[networkName]; exists {
return id, nil
}
if id, err := strconv.ParseUint(networkName, 10, 0); err == nil {
if id > math.MaxUint32 {
return 0, fmt.Errorf("NetworkID %s not in [0, 2^32)", networkName)
}
return uint32(id), nil
}
if validNetworkName.MatchString(networkName) {
if id, err := strconv.Atoi(networkName[8:]); err == nil {
if id > math.MaxUint32 {
return 0, fmt.Errorf("NetworkID %s not in [0, 2^32)", networkName)
}
return uint32(id), nil
}
}
return 0, fmt.Errorf("Failed to parse %s as a network name", networkName)
}

View File

@ -95,7 +95,7 @@ func (b *Bag) Mode() (ID, int) { return b.mode, b.modeFreq }
func (b *Bag) Threshold() Set { return b.metThreshold } func (b *Bag) Threshold() Set { return b.metThreshold }
// Filter returns the bag of ids with the same counts as this bag, except all // Filter returns the bag of ids with the same counts as this bag, except all
// the ids in the returned bag must have the same bits in the range [start, end] // the ids in the returned bag must have the same bits in the range [start, end)
// as id. // as id.
func (b *Bag) Filter(start, end int, id ID) Bag { func (b *Bag) Filter(start, end int, id ID) Bag {
newBag := Bag{} newBag := Bag{}

View File

@ -5,6 +5,7 @@ package ids
import ( import (
"bytes" "bytes"
"reflect"
"testing" "testing"
) )
@ -29,10 +30,6 @@ func TestID(t *testing.T) {
if b := id.Bytes(); !bytes.Equal(hash[:], b) { if b := id.Bytes(); !bytes.Equal(hash[:], b) {
t.Fatalf("ID.Bytes returned wrong bytes") t.Fatalf("ID.Bytes returned wrong bytes")
} }
if str := id.String(); str != "Ba3mm8Ra8JYYebeZ9p7zw1ayorDbeD1euwxhgzSLsncKqGoNt" {
t.Fatalf("ID.String returned wrong string: %s", str)
}
} }
func TestIDBit(t *testing.T) { func TestIDBit(t *testing.T) {
@ -79,3 +76,143 @@ func TestFromString(t *testing.T) {
t.Fatal("Expected FromString to be inverse of String but it wasn't") t.Fatal("Expected FromString to be inverse of String but it wasn't")
} }
} }
func TestIDFromStringError(t *testing.T) {
tests := []struct {
in string
}{
{""},
{"foo"},
{"foobar"},
}
for _, tt := range tests {
t.Run(tt.in, func(t *testing.T) {
_, err := FromString(tt.in)
if err == nil {
t.Error("Unexpected success")
}
})
}
}
func TestIDMarshalJSON(t *testing.T) {
tests := []struct {
label string
in ID
out []byte
err error
}{
{"ID{}", ID{}, []byte("null"), nil},
{"ID(\"ava labs\")",
NewID([32]byte{'a', 'v', 'a', ' ', 'l', 'a', 'b', 's'}),
[]byte("\"jvYi6Tn9idMi7BaymUVi9zWjg5tpmW7trfKG1AYJLKZJ2fsU7\""),
nil,
},
}
for _, tt := range tests {
t.Run(tt.label, func(t *testing.T) {
out, err := tt.in.MarshalJSON()
if err != tt.err {
t.Errorf("Expected err %s, got error %v", tt.err, err)
} else if !bytes.Equal(out, tt.out) {
t.Errorf("got %q, expected %q", out, tt.out)
}
})
}
}
func TestIDUnmarshalJSON(t *testing.T) {
tests := []struct {
label string
in []byte
out ID
err error
}{
{"ID{}", []byte("null"), ID{}, nil},
{"ID(\"ava labs\")",
[]byte("\"jvYi6Tn9idMi7BaymUVi9zWjg5tpmW7trfKG1AYJLKZJ2fsU7\""),
NewID([32]byte{'a', 'v', 'a', ' ', 'l', 'a', 'b', 's'}),
nil,
},
}
for _, tt := range tests {
t.Run(tt.label, func(t *testing.T) {
foo := ID{}
err := foo.UnmarshalJSON(tt.in)
if err != tt.err {
t.Errorf("Expected err %s, got error %v", tt.err, err)
} else if foo.ID != nil && foo.Key() != tt.out.Key() {
t.Errorf("got %q, expected %q", foo.Key(), tt.out.Key())
}
})
}
}
func TestIDHex(t *testing.T) {
id := NewID([32]byte{'a', 'v', 'a', ' ', 'l', 'a', 'b', 's'})
expected := "617661206c61627300000000000000000000000000000000000000000000000000"
actual := id.Hex()
if actual != actual {
t.Fatalf("got %s, expected %s", actual, expected)
}
}
func TestIDString(t *testing.T) {
tests := []struct {
label string
id ID
expected string
}{
{"ID{}", ID{}, "nil"},
{"ID{[32]byte{24}}", NewID([32]byte{24}), "Ba3mm8Ra8JYYebeZ9p7zw1ayorDbeD1euwxhgzSLsncKqGoNt"},
}
for _, tt := range tests {
t.Run(tt.label, func(t *testing.T) {
result := tt.id.String()
if result != tt.expected {
t.Errorf("got %q, expected %q", result, tt.expected)
}
})
}
}
func TestSortIDs(t *testing.T) {
ids := []ID{
NewID([32]byte{'e', 'v', 'a', ' ', 'l', 'a', 'b', 's'}),
NewID([32]byte{'W', 'a', 'l', 'l', 'e', ' ', 'l', 'a', 'b', 's'}),
NewID([32]byte{'a', 'v', 'a', ' ', 'l', 'a', 'b', 's'}),
}
SortIDs(ids)
expected := []ID{
NewID([32]byte{'W', 'a', 'l', 'l', 'e', ' ', 'l', 'a', 'b', 's'}),
NewID([32]byte{'a', 'v', 'a', ' ', 'l', 'a', 'b', 's'}),
NewID([32]byte{'e', 'v', 'a', ' ', 'l', 'a', 'b', 's'}),
}
if !reflect.DeepEqual(ids, expected) {
t.Fatal("[]ID was not sorted lexographically")
}
}
func TestIsSortedAndUnique(t *testing.T) {
unsorted := []ID{
NewID([32]byte{'e', 'v', 'a', ' ', 'l', 'a', 'b', 's'}),
NewID([32]byte{'a', 'v', 'a', ' ', 'l', 'a', 'b', 's'}),
}
if IsSortedAndUniqueIDs(unsorted) {
t.Fatal("Wrongly accepted unsorted IDs")
}
duplicated := []ID{
NewID([32]byte{'a', 'v', 'a', ' ', 'l', 'a', 'b', 's'}),
NewID([32]byte{'a', 'v', 'a', ' ', 'l', 'a', 'b', 's'}),
}
if IsSortedAndUniqueIDs(duplicated) {
t.Fatal("Wrongly accepted duplicated IDs")
}
sorted := []ID{
NewID([32]byte{'a', 'v', 'a', ' ', 'l', 'a', 'b', 's'}),
NewID([32]byte{'e', 'v', 'a', ' ', 'l', 'a', 'b', 's'}),
}
if !IsSortedAndUniqueIDs(sorted) {
t.Fatal("Wrongly rejected sorted, unique IDs")
}
}

70
ids/queue_test.go Normal file
View File

@ -0,0 +1,70 @@
package ids
import (
"reflect"
"testing"
)
func TestQueueSetinit(t *testing.T) {
qs := QueueSet{}
qs.init()
if qs.idList == nil {
t.Fatal("Failed to initialize")
}
list := qs.idList
qs.init()
if list != qs.idList {
t.Fatal("Mutated an already intialized queue")
}
}
func TestQueueSetSetHead(t *testing.T) {
qs := QueueSet{}
id := NewID([32]byte{'a', 'v', 'a', ' ', 'l', 'a', 'b', 's'})
qs.SetHead(id)
if qs.idList == nil || id != qs.idList.Front().Value.(ID) {
t.Fatal("Failed to set head of unintilised queue")
}
qs.SetHead(id)
if qs.idList.Len() != 1 || id != qs.idList.Front().Value.(ID) {
t.Fatal("Mutated a queue which already had the desired head")
}
id2 := NewID([32]byte{'e', 'v', 'a', ' ', 'l', 'a', 'b', 's'})
qs.SetHead(id2)
if qs.idList.Len() != 1 || id2 != qs.idList.Front().Value.(ID) {
t.Fatal("Didn't replace the existing head")
}
}
func TestQueueSetAppend(t *testing.T) {
qs := QueueSet{}
id := NewID([32]byte{'a', 'v', 'a', ' ', 'l', 'a', 'b', 's'})
qs.Append(id)
if qs.idList == nil || id != qs.idList.Front().Value.(ID) {
t.Fatal("Failed to append to an uninitialised queue")
}
id2 := NewID([32]byte{'e', 'v', 'a', ' ', 'l', 'a', 'b', 's'})
qs.Append(id2)
if qs.idList.Len() != 2 || id2 != qs.idList.Back().Value.(ID) {
t.Fatal("Failed to append to the back of the queue")
}
}
func TestQueueGetTail(t *testing.T) {
qs := QueueSet{}
tail := qs.GetTail()
if !reflect.DeepEqual(tail, ID{}) {
t.Fatalf("Empty queue returned %v, expected empty ID %v", tail, Empty)
}
qs.Append(NewID([32]byte{'a', 'v', 'a', ' ', 'l', 'a', 'b', 's'}))
id2 := NewID([32]byte{'e', 'v', 'a', ' ', 'l', 'a', 'b', 's'})
qs.Append(id2)
tail = qs.GetTail()
if tail != id2 {
t.Fatalf("Populated queue returned %v, expected %v", tail, id2)
}
}

View File

@ -1,7 +1,7 @@
#!/bin/sh #!/bin/sh
set -ex set -ex
keypath=$GOPATH/src/github.com/ava-labs/gecko/keys/mykey keypath=$GOPATH/src/github.com/ava-labs/gecko/keys
if test -f "$keypath/staker.key" || test -f "$keypath/staker.crt"; then if test -f "$keypath/staker.key" || test -f "$keypath/staker.crt"; then
echo "staker.key or staker.crt already exists. Not generating new key/certificiate." echo "staker.key or staker.crt already exists. Not generating new key/certificiate."

View File

@ -1,6 +0,0 @@
#!/bin/sh
set -ex
openssl genrsa -out `dirname "$0"`/staker.key 4096
openssl req -new -sha256 -key `dirname "$0"`/staker.key -subj "/C=US/ST=NY/O=Avalabs/CN=ava" -out `dirname "$0"`/staker.csr
openssl x509 -req -in `dirname "$0"`/staker.csr -CA `dirname "$0"`/rootCA.crt -CAkey `dirname "$0"`/rootCA.key -CAcreateserial -out `dirname "$0"`/staker.crt -days 365250 -sha256

View File

@ -1 +0,0 @@
BAF3B5C5C6D0D14A

View File

@ -1,27 +0,0 @@
-----BEGIN CERTIFICATE REQUEST-----
MIIEfzCCAmcCAQAwOjELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAk5ZMRAwDgYDVQQK
DAdBdmFsYWJzMQwwCgYDVQQDDANhdmEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw
ggIKAoICAQDKYSRw/W0YpYH/MTQhiFrR0m89l6yTuzLpDtjudr/5RnhIPvtqk7YI
Gm/m9l29xwR4J5r7SZGs+70yBetkbS+h7PwJ2rmWDwbrdyJKvVBhqf8kSn+VU2Le
PSIcJj193LDyWhV1H4lqNkUkcAR76Fh9qjMvA2p0vJ66+eDLXlph/RYapQx9HgOj
/0BmAKMrYCyo5BhRih+Ougg8aK4G9PQTIA5G2wTWW2QkHxM/QppFjZd/XwQeJ2H6
ubWMFc5fttf6AzpJvFIDBu/JDCKWiCu5m8t4GL8w2OrIx8Js19lF4YYE2eojCreq
gPi64S3ocqwKsDoySTw6/5iKQ5BUYwUXX3z7EXOqD8SMHefUKeczj4WvAaZLzR27
qXm55EgRYQAIX4fhmY7NfSop3Wh0Eo62+JHoM/1g+UgOXlbnWpY95Mgd7/fwDSWL
u4IxE0/uq8VufIbfC4yrY8qlTVfAffI1ldRdvJjPJBPiQ0CNrOl60LVptpkGc9sh
H7wZ2bP0bEnYKTgLAfOzD8Ut71O2AOIa80A1GNFl4Yle/MSNJOcQOSpgtWdREzIU
oenAjfuzM4OeTr4cRg4+VYTAo9KHKriN1DuewNzGd8WjKAVHmcIMjqISLTlzMhds
dm+OmfQ6OvyX7v0GTOBbhP09NGcww5A0gCzXN18FS5oxnxe6OG9D0wIDAQABoAAw
DQYJKoZIhvcNAQELBQADggIBAE7VplAZTEGHpYwXZvhlVg0qDsb/7IQj77eNteSU
33Dq6u7QLgS+Ea04Xv5BHnhnBoWRtrNR8WLTw64cuj6p/sqXiQsSNDgxNDPuPG+g
1FFi6wjgtoIJnx/QrITuUyO/MRy1awKLHlGfbY6yXSdLCC9bqLSIRm0tx+E+jo5C
0r5+ZOcLK8ZXWq9uHjmekX0hoN4qzsbQ0J5IeMh9ag+698aqzBSEDljLHg614yiK
FxtpD+23O0XfAdgqFgXRLLg3tt8AkVuys7r/uwHoz9du+nwW2U5nsMIYBXLV2mq3
1KbpXDTlVwaSoA2LP8dpmvbyTgNbXsjPdS91Rrzd7fcsammcSV0aWPiXmIbTLtn8
61ZRR0uj+jB68cRjSvegnheifsGyq6alr8OSUMdeWVyiPy2O7N6fUVj+Fmyzl5Ph
fl9UPZTmt/zOZrcSBoWjtZfmQVfw29SfMYwlNKALN4eOT6XwBLDK4uu4UXSoXwi+
V8evUUfBWcrcXHMTIFhoZbW/b7gjhnv148XWYI0ta8pjt/akzlPLtf4ETPqfECNN
4+p2w9+R5ktzCLeceXQc8eN+ZwjIt31zG48J7Sl1wJB13VR0jPy6zDsyUIswIVfe
7gp7GHg8R0lzDpEYCvU+R7RUWK6xcpjt7+mTHM70csnnOg7uPqnXqOdtVplr0y+R
pmqJ
-----END CERTIFICATE REQUEST-----

View File

@ -1,5 +0,0 @@
#!/bin/sh
set -ex
openssl genrsa -out `dirname "$0"`/rootCA.key 4096
openssl req -x509 -new -nodes -key `dirname "$0"`/rootCA.key -sha256 -days 365250 -out `dirname "$0"`/rootCA.crt

View File

@ -1,6 +0,0 @@
#!/bin/sh
set -ex
openssl genrsa -out `dirname "$0"`/staker.key 4096
openssl req -new -sha256 -key `dirname "$0"`/staker.key -subj "/C=US/ST=NY/O=Avalabs/CN=ava" -out `dirname "$0"`/staker.csr
openssl x509 -req -in `dirname "$0"`/staker.csr -CA `dirname "$0"`/rootCA.crt -CAkey `dirname "$0"`/rootCA.key -CAcreateserial -out `dirname "$0"`/staker.crt -days 365250 -sha256

View File

@ -1,34 +0,0 @@
-----BEGIN CERTIFICATE-----
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
DB8IRfWqBx2nWw==
-----END CERTIFICATE-----

View File

@ -1,51 +0,0 @@
-----BEGIN RSA PRIVATE KEY-----
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
-----END RSA PRIVATE KEY-----

View File

@ -1 +0,0 @@
BAF3B5C5C6D0D14A

View File

@ -1,27 +0,0 @@
-----BEGIN CERTIFICATE REQUEST-----
MIIEfzCCAmcCAQAwOjELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAk5ZMRAwDgYDVQQK
DAdBdmFsYWJzMQwwCgYDVQQDDANhdmEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw
ggIKAoICAQDdToR60na6NuR9iSAUMyzPXJNMWVQbLyT5/iZCiJ3BB4YWMBhfxpJW
JiWXcM+znDgpJuyCEeh5Dp6ZY3Fe7k6Hht6FmFpDjwnjpQmdkEKUg00G+ElPTp/U
smsPL+JAswPqBZWpMBS3dsXQNunMMtMGlrf5S0l6XX4y7kc/GTxYgveWZ9JtR/m2
KNer+wjgBHqJ4rPqnHB30sDYPZg91Cz1Ak8Bb2w2I108zQVgKK6eIqNKXJJ/4piz
SZdU4920wMxYBpnfDAchnxei9U/v3QbT7eKUI2fGr+hOWTIWU80+VeOBt8a6P4sS
9AQh5/6G8qwmAqO3YQ9dxN82iu/H3+N+GGa/M0r5rEWrzwIuFhwKvyQcpPRBm2yQ
nBnhL9G5kN6n4OBM0KsgZ3CYlHZSg4eWcNgBt1WCFsQc7vfUFaJnr8QP3pF4V/4B
ok7wTO5HN0A1EYEVYuX53NGnrKVe+Fg9+xMOgXPWkUNqdvpI9ZbV3Z0S5866qF3/
vBZrhgCrKc5E/vMexBRe8Ki4wKqONVhi9WGUcRHvFEikc+7VrPj0YaG6zVLd+uOA
JN81fKOPYo4X4sZrMyPYl3OjGtMhfV4KvCaLEr1duOklqO6cCvGQ8iAlLVy3VJyW
5GJ0D0KyiAir4VNdAJKo1ZgiGivJLWulTfjUifCN9o115AiqJxiqwwIDAQABoAAw
DQYJKoZIhvcNAQELBQADggIBAM2IHKsQsebxTD50QQXtSNbyRzG/GpMZuZXn/QYO
QGW0ThJwtcmx6cqQvuyBovH5WhB9QUBFjiKkR7Qef7HUsgxU1cJA75gBfb2GMUru
Q+T37xOxtr6S2TcKOq/LvdJaTYmAHmW9V7vwEcrMRa9lWVTEmJIKTuxiUubpXtup
8OB8WLIvDikVtKtegvl6VCaTApCkUfuLhf7DERQ6sGLXWz6dVQcfvbfcXK2fn1Ik
Koxqy1SSz/rPb4u9NEk1yqvJQdpgnbTM3drTPHiIHCA7F6SjMu5tekHtVQkFOd6c
B0geEwyxY97zqnFv5YXiukXEaAnCRAlOuIZXRqtK6GFthTWo33YpB2KaRUtJ7IuP
og4Q/zjDs8DEc/qbbUbhyulExz6uoyRKO4j/gG3ESC6j09j7Eungt1LDhyt8p3wD
pytIIPkTseykO0CcEpEcGbES6d3u4PrFJ75XWxMkNZVK8mC3faxx2kJLfS1+4Fg8
A0zbcN6qwm1ezGq2vGQcyVKyFVWJQAEAFuSO8sjW6dk3ClfE+MNGUvxTQMe96V14
jGRICCp9aJrJXA3u0iQaUX0cXmlhegAYk7Ho/Ef3k/PcP8DzZ8Ck839oRHBw4pPv
tKbyiKnOcet7AFGwsiM2t5VLrj4jovhRLEiaXrCaxNe6j4xs63TEb+8uTCzKyktC
4BFq
-----END CERTIFICATE REQUEST-----

View File

@ -1,5 +0,0 @@
#!/bin/sh
set -ex
openssl genrsa -out `dirname "$0"`/rootCA.key 4096
openssl req -x509 -new -nodes -key `dirname "$0"`/rootCA.key -sha256 -days 365250 -out `dirname "$0"`/rootCA.crt

View File

@ -1,6 +0,0 @@
#!/bin/sh
set -ex
openssl genrsa -out `dirname "$0"`/staker.key 4096
openssl req -new -sha256 -key `dirname "$0"`/staker.key -subj "/C=US/ST=NY/O=Avalabs/CN=ava" -out `dirname "$0"`/staker.csr
openssl x509 -req -in `dirname "$0"`/staker.csr -CA `dirname "$0"`/rootCA.crt -CAkey `dirname "$0"`/rootCA.key -CAcreateserial -out `dirname "$0"`/staker.crt -days 365250 -sha256

View File

@ -1,34 +0,0 @@
-----BEGIN CERTIFICATE-----
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
DB8IRfWqBx2nWw==
-----END CERTIFICATE-----

View File

@ -1,51 +0,0 @@
-----BEGIN RSA PRIVATE KEY-----
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
-----END RSA PRIVATE KEY-----

View File

@ -1 +0,0 @@
BAF3B5C5C6D0D14A

View File

@ -1,27 +0,0 @@
-----BEGIN CERTIFICATE REQUEST-----
MIIEfzCCAmcCAQAwOjELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAk5ZMRAwDgYDVQQK
DAdBdmFsYWJzMQwwCgYDVQQDDANhdmEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw
ggIKAoICAQC8mVDToHbkUF2gRdVfpydZLNKeQ38d6HZFkUM3U1dWLZFSZNvagN8h
lQvY/tQu3A40p19WgKbzWZre3tg1Akw8Jztdz9gl4RMn142IIO3CiwIptkE0Jopb
ZhmG5fAC2n/MXQtfieI3hzeR04LW4JgLKzf3Nn8xZdlBgJfBmL5qUUnE7O7IbJGG
ma6gSD3ewetE6KQZtNtf0xRIv08doZKYwTl6ItkdGK76ufqq098GVwWvA1wSune4
+MFgs9N4eFJj6Jyt85fiK/cwPx7KRdgYgBzrZQ4EPshRnwWrBTieOOaJvAA2RMxM
EYzKRrJAAsYI1zxtNyqIUaBTcxmaz+NXUGW+wHwITic0Gp/XQm2Lwr/lxIV6OnAl
L3CgbSXirSnoG+eHQ+vDzBAcRDkTAgv/GUIzlfqT2StTK02uIBgJYzvFTG4plHit
ccRfy8wxsh5Z8xG99lmPQQtLsnlQAV+Li06Cb8CH4hUVoiWiVs5QAahqWmv5fpoX
0Es26RyUHXGbjE202pyMMA7jUerUVKMijOoGZtcH6zB4p/dJ0TtToRwOgrA7NCI9
AYVtqVXrXG/udj8ur2r1bTVwIbHsOeTEP3gY0mHRWm2E/bLjt9vbYIRUxR8xWnLk
beBziNTwg+36jdDF+6gu3cUz/nbSn8YY+Y1jjXuM3lqF8iMaAobhuwIDAQABoAAw
DQYJKoZIhvcNAQELBQADggIBAEWU13T1alCni4R36J65TrGfIljW8LGhmWRo5xoV
YW7HxxZ/WTAFSwAv0yHCGq+H/tebRZhvua+c+jP16YBDoAp5neGWW57gLDg+35H5
guLo73p/qM6hyaUGSfyO9D1nS1QX8R0r70TQYbIrVB4uQeTM2pEYR6NYO7bjPEWr
WwC6RnbtnsNGTeoH+LwiM+uY//VB/tUe1u2y6U8HkIXJo7j4+NqUL1xXmYmC6Rph
PNI3MAZUL40z1VX7fn/Vp7+rc0CBUsFMOLfLmSgL8jsQeKuyVAQKA4xzWQ2qeuGV
Bv24rHbnSxYSu8tMs31LZPn+fsvNWB9iU7MEiTUr+8nAPEAANNaBwaD1EUkzC1WC
OcCUpMgkhVuzfHq+eXWnw3cGVvEZ8A4DzOyl1ZFofxBX7IOOv0lmpDQSeEQlmKPF
LdWI2JJM76BjeXI7l5HbOmRJv1kYFwBq/biDxCSmmNX8uHvAj1EgDNXvr/pRw7rT
6yKOLtk1GSCCrrYQijCXRx2u276+j8MtC5i6FVcUoaSYD+nx2+ApOnZlYR7xsJYw
5ECaeDagjHP472FY/fuhy/UwAIFm5gCcVFs3A2M/Iyn+vsAW5WEdh+fwGiWxfw49
Y5KRT8u7BD0R5T5UYxYwzYekEzxsoD3bvQGx/4tboSUxkOd7pVymbuGzIsQ18heI
78pG
-----END CERTIFICATE REQUEST-----

View File

@ -1,5 +0,0 @@
#!/bin/sh
set -ex
openssl genrsa -out `dirname "$0"`/rootCA.key 4096
openssl req -x509 -new -nodes -key `dirname "$0"`/rootCA.key -sha256 -days 365250 -out `dirname "$0"`/rootCA.crt

View File

@ -1,6 +0,0 @@
#!/bin/sh
set -ex
openssl genrsa -out `dirname "$0"`/staker.key 4096
openssl req -new -sha256 -key `dirname "$0"`/staker.key -subj "/C=US/ST=NY/O=Avalabs/CN=ava" -out `dirname "$0"`/staker.csr
openssl x509 -req -in `dirname "$0"`/staker.csr -CA `dirname "$0"`/rootCA.crt -CAkey `dirname "$0"`/rootCA.key -CAcreateserial -out `dirname "$0"`/staker.crt -days 365250 -sha256

View File

@ -1,34 +0,0 @@
-----BEGIN CERTIFICATE-----
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
DB8IRfWqBx2nWw==
-----END CERTIFICATE-----

View File

@ -1,51 +0,0 @@
-----BEGIN RSA PRIVATE KEY-----
MIIJJwIBAAKCAgEAnjlJxZXy2wI0741MgG5Riw+SFyCOunQcTIIdjdcSTGwu4Oq1
6w3K/f1gDTFDczcU/V7b22MV4dYnPLNXw7Uf7rJyj3dAC3OH3EQtgPfTVir7HnnJ
mtKNnE0gLlObPV7BN8PfXmU1HTgzomaqOtK0i4uxYVSbo/g6Bezh1qqfKr1q7g9h
Kt6Nxt7Fbn2srEuvIroBy/4T0DHTihLfeD0qo+aVHHSV+7fHieQgoiX5VorXALkL
AkNhn3UqkRsLxnZi9N5UMf7+HP8y8qXUIRqor/gbkUEoYTJ39sZHExVAXjUbuWIk
tpfM8vJmco7afbVm4mGQD0xl6W3VTQu5BTnTmpTsjNZyYoUQhvUw6tyVoXX0izsd
CUlYrIOjb+F+NIJk7zMft5H0QbMrJDBmHCRgLJwkPjhEoQerqz9nZ0dSWksiBEnu
TXvVM2Qv37Eue27y/WXNOSF6ZI1471qyontVy+mcwcdtBekPEmmLyNOdXwifwSiV
Kpop43r+fPBttInuAd6GCkOELUOVc9HNO3+S1AqU0ZZPlt0129gXJhN31+7vxoll
JsmjyNLZ/KRa4GA6CeVXxWbCkNruIczcQQIHKF/kYoEnWMGVc7VnJ8nuw1Nu5Uzt
RzYmQHgBIp2bcZnewW/3keNJMkBQ5GMTilDV6ziR8NQqrMMcf5sQdoYgYlMCAwEA
AQKCAgAhNota05AoEv2Dr5h4eS/azgjvm+D6GLd8A/AqPxRTQH5SrlJDpiCPUmmg
O1AaVlyslwX1toX4YxjXcBojNdkfJQxRO0oRXU4Oma0nnl4Zf2o5Sn1cZ4hcYAA6
WUiECGjsyMwRp5MPsCV+mKhxMpu9kzRH5xfIwqmDZuc9RZGlyh8xG79c3VzLeyXc
fLsLa9O2qW8JICuOj3cFS9LnDYfu4c85Kuv06+4R7vY+s1P0q65YM3+xGO3cKB8o
WJIPNfityCHKYOl8ssFCGDdAP7VbQuyegBv20z5FafevdM2POPy53HUycwkNkn6Y
243Xx4VyTeKMo4/dATY+NxC+nRXiz4jLna5a7IIIzjAHl2kF6iJVasd3+X/xWHsM
Lx9iDRjERf+J+y58GaDxetXL1C0xm7Rv28yMYVPAzpucvS4i72Xj7X8JkO3az3Qv
/wqBnxj8ouh+5jvT0nqCJsFZwK0F7Dr3na2lSf34XBCTnd9//FfSIY7mDIddxuVF
2rKKOl2KkvbDUuSKVZwdJeAp1CccN6SfLnxKy+436Z5hYzBIeGyejpCMWivDJ2I3
wjs4w4IPobT5dqaSdPYFTKJnoDv62vYbIN3o8pQ3QUXwmRPyKoPuxe7OZZyec43R
WUtajiW6AXjxUoEtPPPHAT/3pGKG2a0VGtDfjLjpp5OtQmteiQKCAQEAz62n9Lh1
POdC4088GEqrGPhq5MUz2j2pOCjEZ7utmD+Lo8x95McCU+jf4UJ+rbaf96dvjPRC
T0Sc6X6IvvQycJubzQe6XX6eyZsr67qpuY2MGze+NvmO4LcCOfNHerRyLK2DoGLW
jQVxJNsBIFo0T7iSuUICbfxKdKxfH+27rPANEvpqS5BJalAfeGPEL0GgUTKQmswc
23Pnu5mkb7TWLKNVq7o/5PxvXyKmJQaFHCV98pqQr/HhXd79dMD12TPZRvsNgPGK
XOsmPtC5RHhbs/Wmdk3X3ihoVezou2VPeWCIrCANCuU0zZBK1igVC3FGeUK8u1Dl
jrTkRsNTLbBiPwKCAQEAwwngBBjbdRCVvUVWIBQBOk/t/6WyeAVH4O/fq32KklW+
/SN5yeZhXjwMrFhSOqFUDipg/C4Imf5S3V+MlXO4lQsZzZa0d0euBIBt0SEcGE8P
rAkGcvwPfISBfYCnPem1ax01ixNJBxWDrgkfHZchywNPFgopiqpYR7X5ttACctCl
KLaDOXn667QmG1icsVgZV3L8gBxEdyjhmUGWFH/auS28oxqhUgiXrUQXbJKCesGD
E39r/SyOAGP5ZtTkWmNDp2+va8lSJwL1Ix+6qvexi/hIIGoFlSh5w+BwnBlxBL4C
cUanaXRtIqQ9rcO/xhZ7izmQzruNARLDPGIJ59MS7QKCAQBGR3wJAssZ2yD1j4DE
r7AK+TYjSODtP+SeDp24hPiQByEYQ0FvRDFzd+Ebd8cqvhyQUGcdiiNOc+et1JYu
GLFhDifBUJYuwYS2sP5B/Z8mHdKF+20xaW6CeSwVtFBCJAJnQCjFA+2bN3Y8hKhy
7FO7jriIXOA5nCEOLq7aPTc/pNSn0XpbK+7MPWUI9qoTW+AG2le5Ks2xLh4DjFDr
RIUeAgAh5xtsQEjoJu+WpAgzqDRg/xFrmS0s+SNIeWw5HqSuspK1SggKvcDpjPTF
SP2vfrfgXSNqGL6GJW/0yqoEZziZFxeS0lH2JphMtK+6eZDhxEXeFdg5XNnLYJor
Yf89AoIBAHbRLESys/c0HFTKybYPGdRhXzcvxXKynOBeoZ9Cgsm1LP3fv9EM5WJY
KMxRnf6Ty7Y5gQ4AKUNPGUI9dFKTxe4ebiC938EOzOd3Ke+OQSRZ/c0rTl98SR7t
Rkmjt77TAq93gufv3rxPEgJTEj6flHmt0V8236nXLqK5LKB/Rg6WJxePYJACTKeM
/u4H5KVxazbIGSUek2MYZ59KwlhIr4HCaDng/kgQbf6jDbYZ5x1LiEO3i50XqIZ6
YTSRG3ApKsz1ECQU6FRVy+sS6FBBR0ti/OWqUS5WEyAOOewO37go3SoPBewLfnTt
I5oZN1pA1hCyCBK5VSRDPucpPqmY/90CggEAbFRUDyEkq9p7/Va/PYJLMe+1zGoy
+jCC1nm5LioxrUdpE+CV1t1cVutnlI3sRD+79oX/zwlwQ+pCx1XOMCmGs4uZUx5f
UtpGnsPamlyQKyQfPam3N4+4gaY9LLPiYCrI/XQh+vZQNlQTStuKLtb0R8+4wEER
KDTtC2cNN5fSnexEifpvq5yK3x6bH66pPyuRE27vVQ7diPar9A+VwkLs+zGbfnWW
MP/zYUbuiatC/LozcYLs/01m3Nu6oYi0OP/nFofepXNpQoZO8jKpnGRVVJ0EfgSe
f3qb9nkygj+gqGWT+PY6H39xKFz0h7dmmcP3Z7CrYXFEFfTCsUgbOKulAA==
-----END RSA PRIVATE KEY-----

View File

@ -1 +0,0 @@
BAF3B5C5C6D0D14A

View File

@ -1,27 +0,0 @@
-----BEGIN CERTIFICATE REQUEST-----
MIIEfzCCAmcCAQAwOjELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAk5ZMRAwDgYDVQQK
DAdBdmFsYWJzMQwwCgYDVQQDDANhdmEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw
ggIKAoICAQDZnDoDHE2nj82xDjH0Tb7OXMqQDHz+zbLidt6MSI1XB3vOAIEiPqrt
enGnqRbVFcm5GZxvxh4YQD8CjKSk1qgZJczs0DPSiGQ8Efl4PGO4xnEbllgL3PUR
PWp7mEV3oh6fxICgQKTBlT671EnFzB5lyJWpumRzvA1vyhBMsY8aO+xdq5LUFltY
zBdvpgLXVaDwHZQ2PQEWtF0d0JO2N0WFFDGNmx6n8pKSeIAVDsTwZCZK+FCeeEyo
GfXsINsc0yCMQslawkfOMqA9yBV3Ji6QmFYKyGYt65MWGNqPA4XrIyliKwCCXwz9
mjaWyN7rAyw9cWlLMODNmDORWzGRZ5290MEAEIZsqjYHVitRTM/RnNIadToZGO0y
5uAkM14cmTvnsK1CP92qtfSisq75W/I91drThoEtTK78UGOl/5Q1YBR08F+tSUWZ
WyHeI6UOBUCGC2bCtmzKMl7vU25lG6mbCR1JuQi6RYpnfMjXH36lV4S7fTvSwwuR
03h2F3H1eFkWNG2lbFrW0dzDCPg3lXwmFQ65hUcQhctznoBz5C1lF2eW03wuVgxi
nnuVlJHjy/GrqmWsASn1PDuVs4k7k6DJfwyHAiA0uxXrGfxYvp7H8j4+2YOmWiWl
5xYgrEDjur5n8Zx46PHQer2Avq3sbEGEe1MCtXJlj3drd5Him3m+NQIDAQABoAAw
DQYJKoZIhvcNAQELBQADggIBAMdZKzx/Qz07D/ISgEe10+XofO5It86g12YJBgGN
4UEnKNk1quJIs0PAwcDNp7G4BpEMuP5xjyf4q976gzAkTg2kcB+LK85eGGSxkxAt
uFQPlFvk85qn4k7wLSx2zkqs47ItvqK5Ev8lLCZ/HfIy+7y57BKqDTvzhXarE3lq
bEZketwQvDcQPN7Ho9gxDMMQDeE2NeDyYhQtCMlX8PnmBRhWZ4CExODMdm8TrTJJ
5HDoj+fXCaSSbXPN25LKYSKOEM4wtzHa91hQK7JGoeHuSS0zFxDwXNKi3sLLtKTH
jsYL/E9bH2NxKPRoHwCJMS0N2jUqnHFyhQUp8VtJlxN0IsPLZGXFapVo4fk2hDpF
OapX0kysLV37KEklVHucQclU5SeTpzoS7gYXqvOJ3Q/IFR6CFAkCHaDggWpB/sVm
OPG6Pt6XXbGNCav9+Am+0q4UD5O1Sbobx+0XJu3VtnuZdn4Mt0uBSL1DZdG9ceig
mGz4bx1kvnzhL1LOAPmxOYqrLCwqJRkRCa+25uRNqBAqWcU48pwoxC3RLyWvy2UN
8Or+TsBzPUldq8yWn3s0/zE8yui6pxzpGUD2TfbUT78O0HJKn5nQjrjVdQZhaA4t
KnrZCz7lIrHRXf2Hbsg/9QgHhcpkknc98z0trNQHncp/kxUvrBJyJGrUh1DEkOSe
f9p0
-----END CERTIFICATE REQUEST-----

View File

@ -1,5 +0,0 @@
#!/bin/sh
set -ex
openssl genrsa -out `dirname "$0"`/rootCA.key 4096
openssl req -x509 -new -nodes -key `dirname "$0"`/rootCA.key -sha256 -days 365250 -out `dirname "$0"`/rootCA.crt

View File

@ -1,6 +0,0 @@
#!/bin/sh
set -ex
openssl genrsa -out `dirname "$0"`/staker.key 4096
openssl req -new -sha256 -key `dirname "$0"`/staker.key -subj "/C=US/ST=NY/O=Avalabs/CN=ava" -out `dirname "$0"`/staker.csr
openssl x509 -req -in `dirname "$0"`/staker.csr -CA `dirname "$0"`/rootCA.crt -CAkey `dirname "$0"`/rootCA.key -CAcreateserial -out `dirname "$0"`/staker.crt -days 365250 -sha256

View File

@ -1,34 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIF1jCCA76gAwIBAgIJALI1DF9cpwfEMA0GCSqGSIb3DQEBCwUAMH8xCzAJBgNV
BAYTAlVTMQswCQYDVQQIDAJOWTEPMA0GA1UEBwwGSXRoYWNhMRAwDgYDVQQKDAdB
dmFsYWJzMQ4wDAYDVQQLDAVHZWNrbzEMMAoGA1UEAwwDYXZhMSIwIAYJKoZIhvcN
AQkBFhNzdGVwaGVuQGF2YWxhYnMub3JnMCAXDTE5MDIyODIwNTkyNFoYDzMwMTkw
MzA4MjA1OTI0WjB/MQswCQYDVQQGEwJVUzELMAkGA1UECAwCTlkxDzANBgNVBAcM
Bkl0aGFjYTEQMA4GA1UECgwHQXZhbGFiczEOMAwGA1UECwwFR2Vja28xDDAKBgNV
BAMMA2F2YTEiMCAGCSqGSIb3DQEJARYTc3RlcGhlbkBhdmFsYWJzLm9yZzCCAiIw
DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAJ45ScWV8tsCNO+NTIBuUYsPkhcg
jrp0HEyCHY3XEkxsLuDqtesNyv39YA0xQ3M3FP1e29tjFeHWJzyzV8O1H+6yco93
QAtzh9xELYD301Yq+x55yZrSjZxNIC5Tmz1ewTfD315lNR04M6JmqjrStIuLsWFU
m6P4OgXs4daqnyq9au4PYSrejcbexW59rKxLryK6Acv+E9Ax04oS33g9KqPmlRx0
lfu3x4nkIKIl+VaK1wC5CwJDYZ91KpEbC8Z2YvTeVDH+/hz/MvKl1CEaqK/4G5FB
KGEyd/bGRxMVQF41G7liJLaXzPLyZnKO2n21ZuJhkA9MZelt1U0LuQU505qU7IzW
cmKFEIb1MOrclaF19Is7HQlJWKyDo2/hfjSCZO8zH7eR9EGzKyQwZhwkYCycJD44
RKEHq6s/Z2dHUlpLIgRJ7k171TNkL9+xLntu8v1lzTkhemSNeO9asqJ7VcvpnMHH
bQXpDxJpi8jTnV8In8EolSqaKeN6/nzwbbSJ7gHehgpDhC1DlXPRzTt/ktQKlNGW
T5bdNdvYFyYTd9fu78aJZSbJo8jS2fykWuBgOgnlV8VmwpDa7iHM3EECByhf5GKB
J1jBlXO1ZyfJ7sNTbuVM7Uc2JkB4ASKdm3GZ3sFv95HjSTJAUORjE4pQ1es4kfDU
KqzDHH+bEHaGIGJTAgMBAAGjUzBRMB0GA1UdDgQWBBQr2T0duSMkvGXe3bSdWcei
73QtwzAfBgNVHSMEGDAWgBQr2T0duSMkvGXe3bSdWcei73QtwzAPBgNVHRMBAf8E
BTADAQH/MA0GCSqGSIb3DQEBCwUAA4ICAQBpP18zCdzvnSdPigg9wx+a8Znr4aJj
FxZYwBY6/BmKb56ke9g+zKKCw2dYYkRYDcTOEfuBgBvNeCSJv4R5rmkukkL8RCIG
XV/WfSn2d3Mnz5KTgGQS6Q9s5qx+8ydkiGZthi+8a8ltXczyYrvWgd47U0NWTcOY
omjgF6XF+hVLWLgiwmA468pd7wyCsuJJkyxxeyDPXQ422I1AJW/7c5JQQa+lDNsv
Vna6420mZ/DiQd3stFkdjhRjmBZvGQ09g6l3zo6TgI1TWr5TMYPrempBVCWPNilC
XaMysU77+tPutI+7kMBuGvLuZtPrH/2uTYdXWPodyORm5i2ABF6In3VISPD9YNc0
gWx3PYGi2BfdnZepCojsffUMlhT3SsiAKMYv5FhW8LQBNMRR4721U1Vf5f8fzNQn
3E55TthV5HXZQ6HcLhkmOvH8CMqtWGETTbBtYSA2AVMjoqs7QDGkfsCH9UuwGd1N
W12JOf53XyOQT2XwWerSQC2kv7elsTh6Bk7PhvrCi0OwCVSGny5IQY/aXM1n6Z6s
scJlZmq6P3AJZ3tRtBt9yDK7iIW7mzNLTb/kAjsNQh06oETJIJ0CIgL0Bn6CANYU
kNqB4oTxmAhdOPKNgqaIwdZAL1VDIVaQEcvGeZRduo7yZvA/MhuQD8IIKSeOBFaD
DB8IRfWqBx2nWw==
-----END CERTIFICATE-----

View File

@ -1,51 +0,0 @@
-----BEGIN RSA PRIVATE KEY-----
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
-----END RSA PRIVATE KEY-----

View File

@ -1 +0,0 @@
BAF3B5C5C6D0D14A

View File

@ -1,27 +0,0 @@
-----BEGIN CERTIFICATE REQUEST-----
MIIEfzCCAmcCAQAwOjELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAk5ZMRAwDgYDVQQK
DAdBdmFsYWJzMQwwCgYDVQQDDANhdmEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw
ggIKAoICAQDgK5r5vdHtJFEgw7hGE/lzKaHcvwzr32armq0k9tYchJXfT3k1j1lX
tBAdcUN3gSRKjgzH/vjbn0ea3AiDCUd2Mck/n0KcJZ43S5I7ZjP7rbav296bKCZ1
Hr7r5gXYFhk+3aUsVfDUqAPBwyP8KeV31ARVA/s+WPeWqs69QXTdyJuBYE5pr40v
1Sf+ebUInZ37uGY3kiO0Ex/JgcoQsGJzrWD/ztbRCFIvrdNJZd0pGvMlmTKp7XsM
R3cpvqk770//MLCdyGW/1IArTSuD1vd7mBX1JyVXKycYN0vIOtbgxPOFutUyqDOe
P7o51q4iPS3dCRgfmn/hWLwy+CtJe0BGKsb4tk0tKxo0se8v9JA8mUtnmzmMt4Y9
jijOrCOB7XwWKmJYEm8N5Ubcy6cp2oL8vQVtzz3PXrkFt+3cFt1jrjdpQYgH4jyk
kWDeOjEfy1FCwzsNRudLTvLhfLn86/ZT4cLZ9JI7/WW0IPC8Fc7lhznJ+bIQUeEn
daGdgVkxuEg0MxdrMr0jU0IFoXySRXNRzcDWZShEjBTv7tnFxLmoNU+uJb/KpMH6
sRYi3zs85ecaMKNyG+LDmBahUlHx5hKAH49O8855+AMhsg91ONZJldjQX0oZrIKz
K5BpsqeTl4c2Yt/fALiZaeFk1pBEsvVeMOBCIuWE+b4UIEaLAOhxfwIDAQABoAAw
DQYJKoZIhvcNAQELBQADggIBAMWzSdk6C53ijuLYOt77BAYpxnxRvKA1tsxJd9K5
+R+ZGiuTLXWArgClhhwx65OTeqrwkVlh2CZoVTBeEMzvxn6zHO4S20KcWJ1lWU76
OIrBZrAecBVXB5LmttUkvlMgVlWLQuVpVJiEn1jW6KeABqWKCLz7Au8TzHfr1HQ4
1ukndu3SsKVwSIy0ZHFpQaXvzA8f0V93ap9R2RVw9BXqCJDe+BtQPvlCwOrvQ7d3
gg+3aymbqUx3hrscEvd1ETad7LyFw3QfPcr1j1FwPH+K1/UDrWxIzxmO+HM5Lh8f
269aYceysgv/xa/KpANTxVAM7j1SE1CjjI5e5CQJVZ+gtAqTIv3lLkk0dWQksObN
Z1tTtJkFAUNbGsMadtVeTmx2eBcRi4LEv0DIPyyWUQTWwTYtaMFi8I0bYPk1T/fV
9umR6jqZ0l1qdiuLYOSYUx4iI5SAmCrA/kEINOj0u2gqqkxdOgUVsuKqer4w9Iyt
qOhhOHwctRo+cIhpVwcF2ouJeNrFqoBzOgHKQxBvcDWJM8ra5GCNIvD3MP4Q63hy
b4fkBcYwb1B2ETH9nSDtfW+JLjt70rvf6IxAiXRRiOv4fPzaUlK49NRVgjzx5Iu+
8Zq4+I+S6qZOROWsOVSpJu44VvNZd5bMB9dEHnkoGxkPjo8pkC/o0uZbxsnZScSL
WGxS
-----END CERTIFICATE REQUEST-----

View File

@ -1,5 +0,0 @@
#!/bin/sh
set -ex
openssl genrsa -out `dirname "$0"`/rootCA.key 4096
openssl req -x509 -new -nodes -key `dirname "$0"`/rootCA.key -sha256 -days 365250 -out `dirname "$0"`/rootCA.crt

View File

@ -1,34 +0,0 @@
-----BEGIN CERTIFICATE-----
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
DB8IRfWqBx2nWw==
-----END CERTIFICATE-----

View File

@ -1,51 +0,0 @@
-----BEGIN RSA PRIVATE KEY-----
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
-----END RSA PRIVATE KEY-----

View File

@ -1 +0,0 @@
BAF3B5C5C6D0D164

1
keys/rootCA.srl Normal file
View File

@ -0,0 +1 @@
BAF3B5C5C6D0D166

View File

@ -8,6 +8,7 @@ import (
"flag" "flag"
"fmt" "fmt"
"net" "net"
"os"
"path" "path"
"strings" "strings"
@ -32,6 +33,22 @@ var (
Err error Err error
) )
// GetIPs returns the default IPs for each network
func GetIPs(networkID uint32) []string {
switch networkID {
case genesis.CascadeID:
return []string{
"3.227.207.132:21001",
"34.207.133.167:21001",
"107.23.241.199:21001",
"54.197.215.186:21001",
"18.234.153.22:21001",
}
default:
return nil
}
}
var ( var (
errBootstrapMismatch = errors.New("more bootstrap IDs provided than bootstrap IPs") errBootstrapMismatch = errors.New("more bootstrap IDs provided than bootstrap IPs")
) )
@ -44,72 +61,81 @@ func init() {
loggingConfig, err := logging.DefaultConfig() loggingConfig, err := logging.DefaultConfig()
errs.Add(err) errs.Add(err)
fs := flag.NewFlagSet("gecko", flag.ContinueOnError)
// NetworkID: // NetworkID:
networkName := flag.String("network-id", genesis.LocalName, "Network ID this node will connect to") networkName := fs.String("network-id", genesis.CascadeName, "Network ID this node will connect to")
// Ava fees: // Ava fees:
flag.Uint64Var(&Config.AvaTxFee, "ava-tx-fee", 0, "Ava transaction fee, in $nAva") fs.Uint64Var(&Config.AvaTxFee, "ava-tx-fee", 0, "Ava transaction fee, in $nAva")
// Assertions: // Assertions:
flag.BoolVar(&loggingConfig.Assertions, "assertions-enabled", true, "Turn on assertion execution") fs.BoolVar(&loggingConfig.Assertions, "assertions-enabled", true, "Turn on assertion execution")
// Crypto: // Crypto:
flag.BoolVar(&Config.EnableCrypto, "signature-verification-enabled", true, "Turn on signature verification") fs.BoolVar(&Config.EnableCrypto, "signature-verification-enabled", true, "Turn on signature verification")
// Database: // Database:
db := flag.Bool("db-enabled", true, "Turn on persistent storage") db := fs.Bool("db-enabled", true, "Turn on persistent storage")
dbDir := flag.String("db-dir", "db", "Database directory for Ava state") dbDir := fs.String("db-dir", "db", "Database directory for Ava state")
// IP: // IP:
consensusIP := flag.String("public-ip", "", "Public IP of this node") consensusIP := fs.String("public-ip", "", "Public IP of this node")
// HTTP Server: // HTTP Server:
httpPort := flag.Uint("http-port", 9650, "Port of the HTTP server") httpPort := fs.Uint("http-port", 9650, "Port of the HTTP server")
flag.BoolVar(&Config.EnableHTTPS, "http-tls-enabled", false, "Upgrade the HTTP server to HTTPs") fs.BoolVar(&Config.EnableHTTPS, "http-tls-enabled", false, "Upgrade the HTTP server to HTTPs")
flag.StringVar(&Config.HTTPSKeyFile, "http-tls-key-file", "", "TLS private key file for the HTTPs server") fs.StringVar(&Config.HTTPSKeyFile, "http-tls-key-file", "", "TLS private key file for the HTTPs server")
flag.StringVar(&Config.HTTPSCertFile, "http-tls-cert-file", "", "TLS certificate file for the HTTPs server") fs.StringVar(&Config.HTTPSCertFile, "http-tls-cert-file", "", "TLS certificate file for the HTTPs server")
// Bootstrapping: // Bootstrapping:
bootstrapIPs := flag.String("bootstrap-ips", "", "Comma separated list of bootstrap peer ips to connect to. Example: 127.0.0.1:9630,127.0.0.1:9631") bootstrapIPs := fs.String("bootstrap-ips", "default", "Comma separated list of bootstrap peer ips to connect to. Example: 127.0.0.1:9630,127.0.0.1:9631")
bootstrapIDs := flag.String("bootstrap-ids", "", "Comma separated list of bootstrap peer ids to connect to. Example: JR4dVmy6ffUGAKCBDkyCbeZbyHQBeDsET,8CrVPQZ4VSqgL8zTdvL14G8HqAfrBr4z") bootstrapIDs := fs.String("bootstrap-ids", "default", "Comma separated list of bootstrap peer ids to connect to. Example: JR4dVmy6ffUGAKCBDkyCbeZbyHQBeDsET,8CrVPQZ4VSqgL8zTdvL14G8HqAfrBr4z")
// Staking: // Staking:
consensusPort := flag.Uint("staking-port", 9651, "Port of the consensus server") consensusPort := fs.Uint("staking-port", 9651, "Port of the consensus server")
flag.BoolVar(&Config.EnableStaking, "staking-tls-enabled", true, "Require TLS to authenticate staking connections") fs.BoolVar(&Config.EnableStaking, "staking-tls-enabled", true, "Require TLS to authenticate staking connections")
flag.StringVar(&Config.StakingKeyFile, "staking-tls-key-file", "", "TLS private key file for staking connections") fs.StringVar(&Config.StakingKeyFile, "staking-tls-key-file", "keys/staker.key", "TLS private key file for staking connections")
flag.StringVar(&Config.StakingCertFile, "staking-tls-cert-file", "", "TLS certificate file for staking connections") fs.StringVar(&Config.StakingCertFile, "staking-tls-cert-file", "keys/staker.crt", "TLS certificate file for staking connections")
// Logging: // Logging:
logsDir := flag.String("log-dir", "", "Logging directory for Ava") logsDir := fs.String("log-dir", "", "Logging directory for Ava")
logLevel := flag.String("log-level", "info", "The log level. Should be one of {verbo, debug, info, warn, error, fatal, off}") logLevel := fs.String("log-level", "info", "The log level. Should be one of {verbo, debug, info, warn, error, fatal, off}")
logDisplayLevel := flag.String("log-display-level", "", "The log display level. If left blank, will inherit the value of log-level. Otherwise, should be one of {verbo, debug, info, warn, error, fatal, off}") logDisplayLevel := fs.String("log-display-level", "", "The log display level. If left blank, will inherit the value of log-level. Otherwise, should be one of {verbo, debug, info, warn, error, fatal, off}")
flag.IntVar(&Config.ConsensusParams.K, "snow-sample-size", 20, "Number of nodes to query for each network poll") fs.IntVar(&Config.ConsensusParams.K, "snow-sample-size", 5, "Number of nodes to query for each network poll")
flag.IntVar(&Config.ConsensusParams.Alpha, "snow-quorum-size", 18, "Alpha value to use for required number positive results") fs.IntVar(&Config.ConsensusParams.Alpha, "snow-quorum-size", 4, "Alpha value to use for required number positive results")
flag.IntVar(&Config.ConsensusParams.BetaVirtuous, "snow-virtuous-commit-threshold", 20, "Beta value to use for virtuous transactions") fs.IntVar(&Config.ConsensusParams.BetaVirtuous, "snow-virtuous-commit-threshold", 20, "Beta value to use for virtuous transactions")
flag.IntVar(&Config.ConsensusParams.BetaRogue, "snow-rogue-commit-threshold", 30, "Beta value to use for rogue transactions") fs.IntVar(&Config.ConsensusParams.BetaRogue, "snow-rogue-commit-threshold", 30, "Beta value to use for rogue transactions")
flag.IntVar(&Config.ConsensusParams.Parents, "snow-avalanche-num-parents", 5, "Number of vertexes for reference from each new vertex") fs.IntVar(&Config.ConsensusParams.Parents, "snow-avalanche-num-parents", 5, "Number of vertexes for reference from each new vertex")
flag.IntVar(&Config.ConsensusParams.BatchSize, "snow-avalanche-batch-size", 30, "Number of operations to batch in each new vertex") fs.IntVar(&Config.ConsensusParams.BatchSize, "snow-avalanche-batch-size", 30, "Number of operations to batch in each new vertex")
fs.IntVar(&Config.ConsensusParams.ConcurrentRepolls, "snow-concurrent-repolls", 1, "Minimum number of concurrent polls for finalizing consensus")
// Enable/Disable APIs: // Enable/Disable APIs:
flag.BoolVar(&Config.AdminAPIEnabled, "api-admin-enabled", true, "If true, this node exposes the Admin API") fs.BoolVar(&Config.AdminAPIEnabled, "api-admin-enabled", true, "If true, this node exposes the Admin API")
flag.BoolVar(&Config.KeystoreAPIEnabled, "api-keystore-enabled", true, "If true, this node exposes the Keystore API") fs.BoolVar(&Config.KeystoreAPIEnabled, "api-keystore-enabled", true, "If true, this node exposes the Keystore API")
flag.BoolVar(&Config.MetricsAPIEnabled, "api-metrics-enabled", true, "If true, this node exposes the Metrics API") fs.BoolVar(&Config.MetricsAPIEnabled, "api-metrics-enabled", true, "If true, this node exposes the Metrics API")
flag.BoolVar(&Config.IPCEnabled, "api-ipcs-enabled", false, "If true, IPCs can be opened") fs.BoolVar(&Config.IPCEnabled, "api-ipcs-enabled", false, "If true, IPCs can be opened")
// Throughput Server // Throughput Server
throughputPort := flag.Uint("xput-server-port", 9652, "Port of the deprecated throughput test server") throughputPort := fs.Uint("xput-server-port", 9652, "Port of the deprecated throughput test server")
flag.BoolVar(&Config.ThroughputServerEnabled, "xput-server-enabled", false, "If true, throughput test server is created") fs.BoolVar(&Config.ThroughputServerEnabled, "xput-server-enabled", false, "If true, throughput test server is created")
flag.Parse() ferr := fs.Parse(os.Args[1:])
if ferr == flag.ErrHelp {
// display usage/help text and exit successfully
os.Exit(0)
}
if ferr != nil {
// other type of error occurred when parsing args
os.Exit(2)
}
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:
@ -143,6 +169,9 @@ func init() {
} }
// Bootstrapping: // Bootstrapping:
if *bootstrapIPs == "default" {
*bootstrapIPs = strings.Join(GetIPs(networkID), ",")
}
for _, ip := range strings.Split(*bootstrapIPs, ",") { for _, ip := range strings.Split(*bootstrapIPs, ",") {
if ip != "" { if ip != "" {
addr, err := utils.ToIPDesc(ip) addr, err := utils.ToIPDesc(ip)
@ -152,6 +181,14 @@ func init() {
}) })
} }
} }
if *bootstrapIDs == "default" {
if *bootstrapIPs == "" {
*bootstrapIDs = ""
} else {
*bootstrapIDs = strings.Join(genesis.GetConfig(networkID).StakerIDs, ",")
}
}
if Config.EnableStaking { if Config.EnableStaking {
i := 0 i := 0
cb58 := formatting.CB58{} cb58 := formatting.CB58{}

View File

@ -54,6 +54,13 @@ Periodically gossip peerlists.
stakers should be in the set). stakers should be in the set).
*/ */
/*
Attempt reconnections
- If a non-staker disconnects, delete the connection
- If a staker disconnects, attempt to reconnect to the node for awhile. If the
node isn't connected to after awhile delete the connection.
*/
const ( const (
// CurrentVersion this avalanche instance is executing. // CurrentVersion this avalanche instance is executing.
CurrentVersion = "avalanche/0.0.1" CurrentVersion = "avalanche/0.0.1"
@ -70,6 +77,9 @@ const (
// GetVersionTimeout is the amount of time to wait before sending a // GetVersionTimeout is the amount of time to wait before sending a
// getVersion message to a partially connected peer // getVersion message to a partially connected peer
GetVersionTimeout = 2 * time.Second GetVersionTimeout = 2 * time.Second
// ReconnectTimeout is the amount of time to wait to reconnect to a staker
// before giving up
ReconnectTimeout = 1 * time.Minute
) )
// Manager is the struct that will be accessed on event calls // Manager is the struct that will be accessed on event calls
@ -100,6 +110,7 @@ type Handshake struct {
connections AddrCert // Connections that I think are connected connections AddrCert // Connections that I think are connected
versionTimeout timer.TimeoutManager versionTimeout timer.TimeoutManager
reconnectTimeout timer.TimeoutManager
peerListGossiper *timer.Repeater peerListGossiper *timer.Repeater
awaitingLock sync.Mutex awaitingLock sync.Mutex
@ -143,6 +154,10 @@ func (nm *Handshake) Initialize(
nm.versionTimeout.Initialize(GetVersionTimeout) nm.versionTimeout.Initialize(GetVersionTimeout)
go nm.log.RecoverAndPanic(nm.versionTimeout.Dispatch) go nm.log.RecoverAndPanic(nm.versionTimeout.Dispatch)
nm.reconnectTimeout.Initialize(ReconnectTimeout)
go nm.log.RecoverAndPanic(nm.reconnectTimeout.Dispatch)
nm.peerListGossiper = timer.NewRepeater(nm.gossipPeerList, PeerListGossipSpacing) nm.peerListGossiper = timer.NewRepeater(nm.gossipPeerList, PeerListGossipSpacing)
go nm.log.RecoverAndPanic(nm.peerListGossiper.Dispatch) go nm.log.RecoverAndPanic(nm.peerListGossiper.Dispatch)
} }
@ -290,6 +305,73 @@ func checkPeerCertificate(_ *C.struct_msgnetwork_conn_t, connected C.bool, _ uns
return connected return connected
} }
func (nm *Handshake) connectedToPeer(conn *C.struct_peernetwork_conn_t, addr salticidae.NetAddr) {
ip := toIPDesc(addr)
// If we're enforcing staking, use a peer's certificate to uniquely identify them
// Otherwise, use a hash of their ip to identify them
cert := ids.ShortID{}
ipCert := toShortID(ip)
if nm.enableStaking {
cert = getPeerCert(conn)
} else {
cert = ipCert
}
nm.log.Debug("Connected to %s", ip)
longCert := cert.LongID()
nm.reconnectTimeout.Remove(longCert)
nm.reconnectTimeout.Remove(ipCert.LongID())
nm.pending.Add(addr, cert)
handler := new(func())
*handler = func() {
if nm.pending.ContainsIP(addr) {
nm.SendGetVersion(addr)
nm.versionTimeout.Put(longCert, *handler)
}
}
(*handler)()
}
func (nm *Handshake) disconnectedFromPeer(addr salticidae.NetAddr) {
cert := ids.ShortID{}
if pendingCert, exists := nm.pending.GetID(addr); exists {
cert = pendingCert
} else if connectedCert, exists := nm.connections.GetID(addr); exists {
cert = connectedCert
} else {
return
}
nm.log.Info("Disconnected from %s", toIPDesc(addr))
longCert := cert.LongID()
if nm.vdrs.Contains(cert) {
nm.reconnectTimeout.Put(longCert, func() {
nm.net.DelPeer(addr)
})
} else {
nm.net.DelPeer(addr)
}
nm.versionTimeout.Remove(longCert)
if !nm.enableStaking {
nm.vdrs.Remove(cert)
}
nm.pending.RemoveIP(addr)
nm.connections.RemoveIP(addr)
nm.numPeers.Set(float64(nm.connections.Len()))
nm.awaitingLock.Lock()
defer nm.awaitingLock.Unlock()
for _, awaiting := range HandshakeNet.awaiting {
awaiting.Remove(cert)
}
}
// peerHandler notifies a change to the set of connected peers // peerHandler notifies a change to the set of connected peers
// connected is true if a new peer is connected // connected is true if a new peer is connected
// connected is false if a formerly connected peer has disconnected // connected is false if a formerly connected peer has disconnected
@ -298,68 +380,30 @@ func peerHandler(_conn *C.struct_peernetwork_conn_t, connected C.bool, _ unsafe.
pConn := salticidae.PeerNetworkConnFromC(salticidae.CPeerNetworkConn(_conn)) pConn := salticidae.PeerNetworkConnFromC(salticidae.CPeerNetworkConn(_conn))
addr := pConn.GetPeerAddr(true) addr := pConn.GetPeerAddr(true)
ip := toIPDesc(addr) if connected {
if !connected { HandshakeNet.connectedToPeer(_conn, addr)
if !HandshakeNet.enableStaking {
cert := toShortID(ip)
HandshakeNet.vdrs.Remove(cert)
}
cert := ids.ShortID{}
if pendingCert, exists := HandshakeNet.pending.GetID(addr); exists {
cert = pendingCert
} else if connectedCert, exists := HandshakeNet.connections.GetID(addr); exists {
cert = connectedCert
} else {
return
}
HandshakeNet.pending.RemoveIP(addr)
HandshakeNet.connections.RemoveIP(addr)
HandshakeNet.numPeers.Set(float64(HandshakeNet.connections.Len()))
HandshakeNet.log.Warn("Disconnected from %s", ip)
HandshakeNet.awaitingLock.Lock()
defer HandshakeNet.awaitingLock.Unlock()
for _, awaiting := range HandshakeNet.awaiting {
awaiting.Remove(cert)
}
return
}
HandshakeNet.log.Debug("Connected to %s", ip)
// If we're enforcing staking, use a peer's certificate to uniquely identify them
// Otherwise, use a hash of their ip to identify them
cert := ids.ShortID{}
if HandshakeNet.enableStaking {
cert = getPeerCert(_conn)
} else { } else {
cert = toShortID(ip) HandshakeNet.disconnectedFromPeer(addr)
} }
HandshakeNet.pending.Add(addr, cert)
certID := cert.LongID()
handler := new(func())
*handler = func() {
if HandshakeNet.pending.ContainsIP(addr) {
HandshakeNet.SendGetVersion(addr)
HandshakeNet.versionTimeout.Put(certID, *handler)
}
}
(*handler)()
} }
// unknownPeerHandler notifies of an unknown peer connection attempt // unknownPeerHandler notifies of an unknown peer connection attempt
//export unknownPeerHandler //export unknownPeerHandler
func unknownPeerHandler(_addr *C.netaddr_t, _cert *C.x509_t, _ unsafe.Pointer) { func unknownPeerHandler(_addr *C.netaddr_t, _cert *C.x509_t, _ unsafe.Pointer) {
addr := salticidae.NetAddrFromC(salticidae.CNetAddr(_addr)) addr := salticidae.NetAddrFromC(salticidae.CNetAddr(_addr)).Copy(true)
ip := toIPDesc(addr) ip := toIPDesc(addr)
HandshakeNet.log.Info("Adding peer %s", ip) HandshakeNet.log.Info("Adding peer %s", ip)
cert := ids.ShortID{}
if HandshakeNet.enableStaking {
cert = getCert(salticidae.X509FromC(salticidae.CX509(_cert)))
} else {
cert = toShortID(ip)
}
HandshakeNet.reconnectTimeout.Put(cert.LongID(), func() {
HandshakeNet.net.DelPeer(addr)
})
HandshakeNet.net.AddPeer(addr) HandshakeNet.net.AddPeer(addr)
} }
@ -522,16 +566,20 @@ func peerList(_msg *C.struct_msg_t, _conn *C.struct_msgnetwork_conn_t, _ unsafe.
cErr := salticidae.NewError() cErr := salticidae.NewError()
for _, ip := range ips { for _, ip := range ips {
HandshakeNet.log.Verbo("Trying to adding peer %s", ip) HandshakeNet.log.Verbo("Trying to adding peer %s", ip)
addr := salticidae.NewNetAddrFromIPPortString(ip.String(), false, &cErr) addr := salticidae.NewNetAddrFromIPPortString(ip.String(), true, &cErr)
if cErr.GetCode() == 0 && !HandshakeNet.myAddr.IsEq(addr) { // Make sure not to connect to myself if cErr.GetCode() == 0 && !HandshakeNet.myAddr.IsEq(addr) { // Make sure not to connect to myself
ip := toIPDesc(addr) ip := toIPDesc(addr)
ipCert := toShortID(ip)
if !HandshakeNet.pending.ContainsIP(addr) && !HandshakeNet.connections.ContainsIP(addr) { if !HandshakeNet.pending.ContainsIP(addr) && !HandshakeNet.connections.ContainsIP(addr) {
HandshakeNet.log.Debug("Adding peer %s", ip) HandshakeNet.log.Debug("Adding peer %s", ip)
HandshakeNet.reconnectTimeout.Put(ipCert.LongID(), func() {
HandshakeNet.net.DelPeer(addr)
})
HandshakeNet.net.AddPeer(addr) HandshakeNet.net.AddPeer(addr)
} }
} }
addr.Free()
} }
} }

View File

@ -366,9 +366,9 @@ func (s *Voting) PullQuery(validatorIDs ids.ShortSet, chainID ids.ID, requestID
vID := validatorID vID := validatorID
if addr, exists := s.conns.GetIP(vID); exists { if addr, exists := s.conns.GetIP(vID); exists {
addrs = append(addrs, addr) addrs = append(addrs, addr)
s.log.Verbo("Sending a PushQuery to %s", toIPDesc(addr)) s.log.Verbo("Sending a PullQuery to %s", toIPDesc(addr))
} else { } else {
s.log.Warn("Attempted to send a PushQuery message to a disconnected validator: %s", vID) s.log.Warn("Attempted to send a PullQuery message to a disconnected validator: %s", vID)
s.executor.Add(func() { s.router.QueryFailed(vID, chainID, requestID) }) s.executor.Add(func() { s.router.QueryFailed(vID, chainID, requestID) })
} }
} }

View File

@ -25,6 +25,7 @@ import (
"github.com/ava-labs/gecko/api/keystore" "github.com/ava-labs/gecko/api/keystore"
"github.com/ava-labs/gecko/api/metrics" "github.com/ava-labs/gecko/api/metrics"
"github.com/ava-labs/gecko/chains" "github.com/ava-labs/gecko/chains"
"github.com/ava-labs/gecko/chains/atomic"
"github.com/ava-labs/gecko/database" "github.com/ava-labs/gecko/database"
"github.com/ava-labs/gecko/database/prefixdb" "github.com/ava-labs/gecko/database/prefixdb"
"github.com/ava-labs/gecko/genesis" "github.com/ava-labs/gecko/genesis"
@ -35,10 +36,13 @@ import (
"github.com/ava-labs/gecko/snow/validators" "github.com/ava-labs/gecko/snow/validators"
"github.com/ava-labs/gecko/utils/hashing" "github.com/ava-labs/gecko/utils/hashing"
"github.com/ava-labs/gecko/utils/logging" "github.com/ava-labs/gecko/utils/logging"
"github.com/ava-labs/gecko/utils/wrappers"
"github.com/ava-labs/gecko/vms" "github.com/ava-labs/gecko/vms"
"github.com/ava-labs/gecko/vms/avm" "github.com/ava-labs/gecko/vms/avm"
"github.com/ava-labs/gecko/vms/evm" "github.com/ava-labs/gecko/vms/evm"
"github.com/ava-labs/gecko/vms/nftfx"
"github.com/ava-labs/gecko/vms/platformvm" "github.com/ava-labs/gecko/vms/platformvm"
"github.com/ava-labs/gecko/vms/propertyfx"
"github.com/ava-labs/gecko/vms/secp256k1fx" "github.com/ava-labs/gecko/vms/secp256k1fx"
"github.com/ava-labs/gecko/vms/spchainvm" "github.com/ava-labs/gecko/vms/spchainvm"
"github.com/ava-labs/gecko/vms/spdagvm" "github.com/ava-labs/gecko/vms/spdagvm"
@ -49,6 +53,10 @@ const (
maxMessageSize = 1 << 25 // maximum size of a message sent with salticidae maxMessageSize = 1 << 25 // maximum size of a message sent with salticidae
) )
var (
genesisHashKey = []byte("genesisID")
)
// MainNode is the reference for node callbacks // MainNode is the reference for node callbacks
var MainNode = Node{} var MainNode = Node{}
@ -68,6 +76,9 @@ type Node struct {
// Handles calls to Keystore API // Handles calls to Keystore API
keystoreServer keystore.Keystore keystoreServer keystore.Keystore
// Manages shared memory
sharedMemory atomic.SharedMemory
// Manages creation of blockchains and routing messages to them // Manages creation of blockchains and routing messages to them
chainManager chains.Manager chainManager chains.Manager
@ -285,7 +296,38 @@ func (n *Node) Dispatch() { n.EC.Dispatch() }
****************************************************************************** ******************************************************************************
*/ */
func (n *Node) initDatabase() { n.DB = n.Config.DB } func (n *Node) initDatabase() error {
n.DB = n.Config.DB
expectedGenesis, err := genesis.Genesis(n.Config.NetworkID)
if err != nil {
return err
}
rawExpectedGenesisHash := hashing.ComputeHash256(expectedGenesis)
rawGenesisHash, err := n.DB.Get(genesisHashKey)
if err == database.ErrNotFound {
rawGenesisHash = rawExpectedGenesisHash
err = n.DB.Put(genesisHashKey, rawGenesisHash)
}
if err != nil {
return err
}
genesisHash, err := ids.ToID(rawGenesisHash)
if err != nil {
return err
}
expectedGenesisHash, err := ids.ToID(rawExpectedGenesisHash)
if err != nil {
return err
}
if !genesisHash.Equals(expectedGenesisHash) {
return fmt.Errorf("db contains invalid genesis hash. DB Genesis: %s Generated Genesis: %s", genesisHash, expectedGenesisHash)
}
return nil
}
// Initialize this node's ID // Initialize this node's ID
// If staking is disabled, a node's ID is a hash of its IP // If staking is disabled, a node's ID is a hash of its IP
@ -320,14 +362,29 @@ func (n *Node) initNodeID() error {
// AVM, EVM, Simple Payments DAG, Simple Payments Chain // AVM, EVM, Simple Payments DAG, Simple Payments Chain
// The Platform VM is registered in initStaking because // The Platform VM is registered in initStaking because
// its factory needs to reference n.chainManager, which is nil right now // its factory needs to reference n.chainManager, which is nil right now
func (n *Node) initVMManager() { func (n *Node) initVMManager() error {
avaAssetID, err := genesis.AVAAssetID(n.Config.NetworkID)
if err != nil {
return err
}
n.vmManager = vms.NewManager(&n.APIServer, n.HTTPLog) n.vmManager = vms.NewManager(&n.APIServer, n.HTTPLog)
n.vmManager.RegisterVMFactory(avm.ID, &avm.Factory{})
n.vmManager.RegisterVMFactory(evm.ID, &evm.Factory{}) errs := wrappers.Errs{}
n.vmManager.RegisterVMFactory(spdagvm.ID, &spdagvm.Factory{TxFee: n.Config.AvaTxFee}) errs.Add(
n.vmManager.RegisterVMFactory(spchainvm.ID, &spchainvm.Factory{}) n.vmManager.RegisterVMFactory(avm.ID, &avm.Factory{
n.vmManager.RegisterVMFactory(secp256k1fx.ID, &secp256k1fx.Factory{}) AVA: avaAssetID,
n.vmManager.RegisterVMFactory(timestampvm.ID, &timestampvm.Factory{}) Platform: ids.Empty,
}),
n.vmManager.RegisterVMFactory(evm.ID, &evm.Factory{}),
n.vmManager.RegisterVMFactory(spdagvm.ID, &spdagvm.Factory{TxFee: n.Config.AvaTxFee}),
n.vmManager.RegisterVMFactory(spchainvm.ID, &spchainvm.Factory{}),
n.vmManager.RegisterVMFactory(timestampvm.ID, &timestampvm.Factory{}),
n.vmManager.RegisterVMFactory(secp256k1fx.ID, &secp256k1fx.Factory{}),
n.vmManager.RegisterVMFactory(nftfx.ID, &nftfx.Factory{}),
n.vmManager.RegisterVMFactory(propertyfx.ID, &propertyfx.Factory{}),
)
return errs.Err
} }
// Create the EventDispatcher used for hooking events // Create the EventDispatcher used for hooking events
@ -343,38 +400,64 @@ func (n *Node) initEventDispatcher() {
// Initializes the Platform chain. // Initializes the Platform chain.
// Its genesis data specifies the other chains that should // Its genesis data specifies the other chains that should
// be created. // be created.
func (n *Node) initChains() { func (n *Node) initChains() error {
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)
} }
n.vmManager.RegisterVMFactory( avaAssetID, err := genesis.AVAAssetID(n.Config.NetworkID)
if err != nil {
return err
}
createAVMTx, err := genesis.VMGenesis(n.Config.NetworkID, avm.ID)
if err != nil {
return err
}
err = 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,
StakingEnabled: n.Config.EnableStaking,
AVA: avaAssetID,
AVM: createAVMTx.ID(),
}, },
) )
if err != nil {
return err
}
beacons := validators.NewSet() beacons := validators.NewSet()
for _, peer := range n.Config.BootstrapPeers { for _, peer := range n.Config.BootstrapPeers {
beacons.Add(validators.NewValidator(peer.ID, 1)) beacons.Add(validators.NewValidator(peer.ID, 1))
} }
genesisBytes := genesis.Genesis(n.Config.NetworkID) genesisBytes, err := genesis.Genesis(n.Config.NetworkID)
if err != nil {
return err
}
// 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,
}) })
return nil
} }
// initAPIServer initializes the server that handles HTTP calls // initAPIServer initializes the server that handles HTTP calls
@ -400,6 +483,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,
@ -415,12 +499,20 @@ func (n *Node) initChainManager() {
n.ValidatorAPI, n.ValidatorAPI,
&n.APIServer, &n.APIServer,
&n.keystoreServer, &n.keystoreServer,
&n.sharedMemory,
) )
n.chainManager.AddRegistrant(&n.APIServer) n.chainManager.AddRegistrant(&n.APIServer)
} }
// initWallet initializes the Wallet service // initSharedMemory initializes the shared memory for cross chain interation
func (n *Node) initSharedMemory() {
n.Log.Info("initializing SharedMemory")
sharedMemoryDB := prefixdb.New([]byte("shared memory"), n.DB)
n.sharedMemory.Initialize(n.Log, sharedMemoryDB)
}
// initKeystoreAPI initializes the keystore service
// Assumes n.APIServer is already set // Assumes n.APIServer is already set
func (n *Node) initKeystoreAPI() { func (n *Node) initKeystoreAPI() {
n.Log.Info("initializing Keystore API") n.Log.Info("initializing Keystore API")
@ -464,24 +556,35 @@ func (n *Node) initIPCAPI() {
} }
// Give chains and VMs aliases as specified by the genesis information // Give chains and VMs aliases as specified by the genesis information
func (n *Node) initAliases() { func (n *Node) initAliases() error {
n.Log.Info("initializing aliases") n.Log.Info("initializing aliases")
defaultAliases, chainAliases, vmAliases := genesis.Aliases(n.Config.NetworkID) defaultAliases, chainAliases, vmAliases, err := genesis.Aliases(n.Config.NetworkID)
if err != nil {
return err
}
for chainIDKey, aliases := range chainAliases { for chainIDKey, aliases := range chainAliases {
chainID := ids.NewID(chainIDKey) chainID := ids.NewID(chainIDKey)
for _, alias := range aliases { for _, alias := range aliases {
n.Log.AssertNoError(n.chainManager.Alias(chainID, alias)) if err := n.chainManager.Alias(chainID, alias); err != nil {
return err
}
} }
} }
for vmIDKey, aliases := range vmAliases { for vmIDKey, aliases := range vmAliases {
vmID := ids.NewID(vmIDKey) vmID := ids.NewID(vmIDKey)
for _, alias := range aliases { for _, alias := range aliases {
n.Log.AssertNoError(n.vmManager.Alias(vmID, alias)) if err := n.vmManager.Alias(vmID, alias); err != nil {
return err
}
} }
} }
for url, aliases := range defaultAliases { for url, aliases := range defaultAliases {
n.APIServer.AddAliases(url, aliases...) if err := n.APIServer.AddAliases(url, aliases...); err != nil {
return err
}
} }
return nil
} }
// Initialize this node // Initialize this node
@ -496,12 +599,17 @@ func (n *Node) Initialize(Config *Config, logger logging.Logger, logFactory logg
} }
n.HTTPLog = httpLog n.HTTPLog = httpLog
n.initDatabase() // Set up the node's database if err := n.initDatabase(); err != nil { // Set up the node's database
return fmt.Errorf("problem initializing database: %w", err)
}
if err = n.initNodeID(); err != nil { // Derive this node's ID if err = n.initNodeID(); err != nil { // Derive this node's ID
return fmt.Errorf("problem initializing staker ID: %w", err) return fmt.Errorf("problem initializing staker ID: %w", err)
} }
// initialize shared memory
n.initSharedMemory()
// Start HTTP APIs // Start HTTP APIs
n.initAPIServer() // Start the API Server n.initAPIServer() // Start the API Server
n.initKeystoreAPI() // Start the Keystore API n.initKeystoreAPI() // Start the Keystore API
@ -511,8 +619,13 @@ func (n *Node) Initialize(Config *Config, logger logging.Logger, logFactory logg
if err = n.initNetlib(); err != nil { // Set up all networking if err = n.initNetlib(); err != nil { // Set up all networking
return fmt.Errorf("problem initializing networking: %w", err) return fmt.Errorf("problem initializing networking: %w", err)
} }
n.initValidatorNet() // Set up the validator handshake + authentication if err := n.initValidatorNet(); err != nil { // Set up the validator handshake + authentication
n.initVMManager() // Set up the vm manager return fmt.Errorf("problem initializing validator network: %w", err)
}
if err := n.initVMManager(); err != nil { // Set up the vm manager
return fmt.Errorf("problem initializing the VM manager: %w", err)
}
n.initEventDispatcher() // Set up the event dipatcher n.initEventDispatcher() // Set up the event dipatcher
n.initChainManager() // Set up the chain manager n.initChainManager() // Set up the chain manager
n.initConsensusNet() // Set up the main consensus network n.initConsensusNet() // Set up the main consensus network
@ -524,10 +637,11 @@ func (n *Node) Initialize(Config *Config, logger logging.Logger, logFactory logg
n.initAdminAPI() // Start the Admin API n.initAdminAPI() // Start the Admin API
n.initIPCAPI() // Start the IPC API n.initIPCAPI() // Start the IPC API
n.initAliases() // Set up aliases
n.initChains() // Start the Platform chain
return nil if err := n.initAliases(); err != nil { // Set up aliases
return err
}
return n.initChains() // Start the Platform chain
} }
// Shutdown this node // Shutdown this node

View File

@ -2,8 +2,6 @@ borealis_bootstrap:
hosts: hosts:
bootstrap1: bootstrap1:
ansible_host: 3.227.207.132 ansible_host: 3.227.207.132
staking_tls_key_file: "/home/ubuntu/go/src/github.com/ava-labs/gecko/keys/keys1/staker.key"
staking_tls_cert_file: "/home/ubuntu/go/src/github.com/ava-labs/gecko/keys/keys1/staker.crt"
http_tls_enabled: true http_tls_enabled: true
http_tls_key_file: "/home/ubuntu/ssl/privkey.pem" http_tls_key_file: "/home/ubuntu/ssl/privkey.pem"
http_tls_cert_file: "/home/ubuntu/ssl/fullchain.pem" http_tls_cert_file: "/home/ubuntu/ssl/fullchain.pem"
@ -11,7 +9,7 @@ borealis_bootstrap:
ansible_connection: ssh ansible_connection: ssh
ansible_user: ubuntu ansible_user: ubuntu
network_id: "borealis" network_id: "cascade"
api_admin_enabled: true api_admin_enabled: true
api_keystore_enabled: true api_keystore_enabled: true
api_metrics_enabled: true api_metrics_enabled: true
@ -28,6 +26,8 @@ borealis_bootstrap:
bootstrap_ids: "" bootstrap_ids: ""
staking_port: 21001 staking_port: 21001
staking_tls_enabled: true staking_tls_enabled: true
staking_tls_key_file: "/home/ubuntu/keys/staker.key"
staking_tls_cert_file: "/home/ubuntu/keys/staker.crt"
log_dir: "/home/ubuntu/.gecko" log_dir: "/home/ubuntu/.gecko"
log_level: debug log_level: debug
snow_sample_size: 3 snow_sample_size: 3
@ -44,25 +44,17 @@ borealis_node:
hosts: hosts:
node1: node1:
ansible_host: 34.207.133.167 ansible_host: 34.207.133.167
staking_tls_key_file: "/home/ubuntu/go/src/github.com/ava-labs/gecko/keys/keys2/staker.key"
staking_tls_cert_file: "/home/ubuntu/go/src/github.com/ava-labs/gecko/keys/keys2/staker.crt"
node2: node2:
ansible_host: 107.23.241.199 ansible_host: 107.23.241.199
staking_tls_key_file: "/home/ubuntu/go/src/github.com/ava-labs/gecko/keys/keys3/staker.key"
staking_tls_cert_file: "/home/ubuntu/go/src/github.com/ava-labs/gecko/keys/keys3/staker.crt"
node3: node3:
ansible_host: 54.197.215.186 ansible_host: 54.197.215.186
staking_tls_key_file: "/home/ubuntu/go/src/github.com/ava-labs/gecko/keys/keys4/staker.key"
staking_tls_cert_file: "/home/ubuntu/go/src/github.com/ava-labs/gecko/keys/keys4/staker.crt"
node4: node4:
ansible_host: 18.234.153.22 ansible_host: 18.234.153.22
staking_tls_key_file: "/home/ubuntu/go/src/github.com/ava-labs/gecko/keys/keys5/staker.key"
staking_tls_cert_file: "/home/ubuntu/go/src/github.com/ava-labs/gecko/keys/keys5/staker.crt"
vars: vars:
ansible_connection: ssh ansible_connection: ssh
ansible_user: ubuntu ansible_user: ubuntu
network_id: "borealis" network_id: "cascade"
api_admin_enabled: true api_admin_enabled: true
api_keystore_enabled: true api_keystore_enabled: true
api_metrics_enabled: true api_metrics_enabled: true
@ -76,9 +68,11 @@ borealis_node:
http_tls_key_file: "" http_tls_key_file: ""
http_tls_cert_file: "" http_tls_cert_file: ""
bootstrap_ips: "3.227.207.132:21001" bootstrap_ips: "3.227.207.132:21001"
bootstrap_ids: "7Xhw2mDxuDS44j42TCB6U5579esbSt3Lg" bootstrap_ids: "NX4zVkuiRJZYe6Nzzav7GXN3TakUet3Co"
staking_port: 21001 staking_port: 21001
staking_tls_enabled: true staking_tls_enabled: true
staking_tls_key_file: "/home/ubuntu/keys/staker.key"
staking_tls_cert_file: "/home/ubuntu/keys/staker.crt"
log_dir: "/home/ubuntu/.gecko" log_dir: "/home/ubuntu/.gecko"
log_level: debug log_level: debug
snow_sample_size: 3 snow_sample_size: 3

View File

@ -8,6 +8,7 @@
ava_binary: ~/go/src/github.com/ava-labs/gecko/build/ava ava_binary: ~/go/src/github.com/ava-labs/gecko/build/ava
repo_folder: ~/go/src/github.com/ava-labs/gecko repo_folder: ~/go/src/github.com/ava-labs/gecko
repo_name: ava-labs/gecko repo_name: ava-labs/gecko
repo_branch: cascade
tasks: tasks:
- name: Kill Node - name: Kill Node
command: killall ava command: killall ava
@ -15,6 +16,7 @@
- git: - git:
repo: ssh://git@github.com/{{ repo_name }}.git repo: ssh://git@github.com/{{ repo_name }}.git
dest: "{{ repo_folder }}" dest: "{{ repo_folder }}"
version: "{{ repo_branch }}"
update: yes update: yes
- name: Build project - name: Build project
command: ./scripts/build.sh command: ./scripts/build.sh

View File

@ -8,6 +8,7 @@
ava_binary: ~/go/src/github.com/ava-labs/gecko/build/ava ava_binary: ~/go/src/github.com/ava-labs/gecko/build/ava
repo_folder: ~/go/src/github.com/ava-labs/gecko repo_folder: ~/go/src/github.com/ava-labs/gecko
repo_name: ava-labs/gecko repo_name: ava-labs/gecko
repo_branch: cascade
tasks: tasks:
- name: Kill Node - name: Kill Node
command: killall ava command: killall ava
@ -15,6 +16,7 @@
- git: - git:
repo: ssh://git@github.com/{{ repo_name }}.git repo: ssh://git@github.com/{{ repo_name }}.git
dest: "{{ repo_folder }}" dest: "{{ repo_folder }}"
version: "{{ repo_branch }}"
update: yes update: yes
- name: Build project - name: Build project
command: ./scripts/build.sh command: ./scripts/build.sh

27
scripts/aws/create.py Normal file → Executable file
View File

@ -1,17 +1,16 @@
import sys #!/usr/bin/env python3
"""
Start a number of AVA nodes on Amazon EC2
"""
import boto3 import boto3
ec2 = boto3.client("ec2")
# Should be called with python3 aws_create.py $numBootstraps $numNodes
numBootstraps = int(sys.argv[1])
numNodes = int(sys.argv[2])
bootstapNode = "Borealis-Bootstrap" bootstapNode = "Borealis-Bootstrap"
fullNode = "Borealis-Node" fullNode = "Borealis-Node"
def runInstances(num: int, name: str): def runInstances(ec2, num: int, name: str):
if num > 0: if num > 0:
ec2.run_instances( ec2.run_instances(
ImageId="ami-0badd1c10cb7673e9", ImageId="ami-0badd1c10cb7673e9",
@ -28,8 +27,18 @@ def runInstances(num: int, name: str):
def main(): def main():
runInstances(numBootstraps, bootstapNode) import argparse
runInstances(numNodes, fullNode)
parser = argparse.ArgumentParser(
description=__doc__,
)
parser.add_argument('numBootstraps', type=int)
parser.add_argument('numNodes', type=int)
args = parser.parse_args()
ec2 = boto3.client("ec2")
runInstances(ec2, args.numBootstraps, bootstapNode)
runInstances(ec2, args.numNodes, fullNode)
if __name__ == "__main__": if __name__ == "__main__":

View File

@ -12,10 +12,11 @@ import (
func TestParametersValid(t *testing.T) { func TestParametersValid(t *testing.T) {
p := Parameters{ p := Parameters{
Parameters: snowball.Parameters{ Parameters: snowball.Parameters{
K: 1, K: 1,
Alpha: 1, Alpha: 1,
BetaVirtuous: 1, BetaVirtuous: 1,
BetaRogue: 1, BetaRogue: 1,
ConcurrentRepolls: 1,
}, },
Parents: 2, Parents: 2,
BatchSize: 1, BatchSize: 1,
@ -29,10 +30,11 @@ func TestParametersValid(t *testing.T) {
func TestParametersInvalidParents(t *testing.T) { func TestParametersInvalidParents(t *testing.T) {
p := Parameters{ p := Parameters{
Parameters: snowball.Parameters{ Parameters: snowball.Parameters{
K: 1, K: 1,
Alpha: 1, Alpha: 1,
BetaVirtuous: 1, BetaVirtuous: 1,
BetaRogue: 1, BetaRogue: 1,
ConcurrentRepolls: 1,
}, },
Parents: 1, Parents: 1,
BatchSize: 1, BatchSize: 1,
@ -46,10 +48,11 @@ func TestParametersInvalidParents(t *testing.T) {
func TestParametersInvalidBatchSize(t *testing.T) { func TestParametersInvalidBatchSize(t *testing.T) {
p := Parameters{ p := Parameters{
Parameters: snowball.Parameters{ Parameters: snowball.Parameters{
K: 1, K: 1,
Alpha: 1, Alpha: 1,
BetaVirtuous: 1, BetaVirtuous: 1,
BetaRogue: 1, BetaRogue: 1,
ConcurrentRepolls: 1,
}, },
Parents: 2, Parents: 2,
BatchSize: 0, BatchSize: 0,

View File

@ -27,11 +27,12 @@ func TestTopologicalTxIssued(t *testing.T) { TxIssuedTest(t, TopologicalFactory{
func TestAvalancheVoting(t *testing.T) { func TestAvalancheVoting(t *testing.T) {
params := Parameters{ params := Parameters{
Parameters: snowball.Parameters{ Parameters: snowball.Parameters{
Metrics: prometheus.NewRegistry(), Metrics: prometheus.NewRegistry(),
K: 2, K: 2,
Alpha: 2, Alpha: 2,
BetaVirtuous: 1, BetaVirtuous: 1,
BetaRogue: 2, BetaRogue: 2,
ConcurrentRepolls: 1,
}, },
Parents: 2, Parents: 2,
BatchSize: 1, BatchSize: 1,
@ -106,11 +107,12 @@ func TestAvalancheVoting(t *testing.T) {
func TestAvalancheTransitiveVoting(t *testing.T) { func TestAvalancheTransitiveVoting(t *testing.T) {
params := Parameters{ params := Parameters{
Parameters: snowball.Parameters{ Parameters: snowball.Parameters{
Metrics: prometheus.NewRegistry(), Metrics: prometheus.NewRegistry(),
K: 2, K: 2,
Alpha: 2, Alpha: 2,
BetaVirtuous: 1, BetaVirtuous: 1,
BetaRogue: 2, BetaRogue: 2,
ConcurrentRepolls: 1,
}, },
Parents: 2, Parents: 2,
BatchSize: 1, BatchSize: 1,
@ -199,11 +201,12 @@ func TestAvalancheTransitiveVoting(t *testing.T) {
func TestAvalancheSplitVoting(t *testing.T) { func TestAvalancheSplitVoting(t *testing.T) {
params := Parameters{ params := Parameters{
Parameters: snowball.Parameters{ Parameters: snowball.Parameters{
Metrics: prometheus.NewRegistry(), Metrics: prometheus.NewRegistry(),
K: 2, K: 2,
Alpha: 2, Alpha: 2,
BetaVirtuous: 1, BetaVirtuous: 1,
BetaRogue: 2, BetaRogue: 2,
ConcurrentRepolls: 1,
}, },
Parents: 2, Parents: 2,
BatchSize: 1, BatchSize: 1,
@ -262,11 +265,12 @@ func TestAvalancheSplitVoting(t *testing.T) {
func TestAvalancheTransitiveRejection(t *testing.T) { func TestAvalancheTransitiveRejection(t *testing.T) {
params := Parameters{ params := Parameters{
Parameters: snowball.Parameters{ Parameters: snowball.Parameters{
Metrics: prometheus.NewRegistry(), Metrics: prometheus.NewRegistry(),
K: 2, K: 2,
Alpha: 2, Alpha: 2,
BetaVirtuous: 1, BetaVirtuous: 1,
BetaRogue: 2, BetaRogue: 2,
ConcurrentRepolls: 1,
}, },
Parents: 2, Parents: 2,
BatchSize: 1, BatchSize: 1,
@ -363,11 +367,12 @@ func TestAvalancheTransitiveRejection(t *testing.T) {
func TestAvalancheVirtuous(t *testing.T) { func TestAvalancheVirtuous(t *testing.T) {
params := Parameters{ params := Parameters{
Parameters: snowball.Parameters{ Parameters: snowball.Parameters{
Metrics: prometheus.NewRegistry(), Metrics: prometheus.NewRegistry(),
K: 2, K: 2,
Alpha: 2, Alpha: 2,
BetaVirtuous: 1, BetaVirtuous: 1,
BetaRogue: 2, BetaRogue: 2,
ConcurrentRepolls: 1,
}, },
Parents: 2, Parents: 2,
BatchSize: 1, BatchSize: 1,
@ -484,11 +489,12 @@ func TestAvalancheVirtuous(t *testing.T) {
func TestAvalancheIsVirtuous(t *testing.T) { func TestAvalancheIsVirtuous(t *testing.T) {
params := Parameters{ params := Parameters{
Parameters: snowball.Parameters{ Parameters: snowball.Parameters{
Metrics: prometheus.NewRegistry(), Metrics: prometheus.NewRegistry(),
K: 2, K: 2,
Alpha: 2, Alpha: 2,
BetaVirtuous: 1, BetaVirtuous: 1,
BetaRogue: 2, BetaRogue: 2,
ConcurrentRepolls: 1,
}, },
Parents: 2, Parents: 2,
BatchSize: 1, BatchSize: 1,
@ -567,11 +573,12 @@ func TestAvalancheIsVirtuous(t *testing.T) {
func TestAvalancheQuiesce(t *testing.T) { func TestAvalancheQuiesce(t *testing.T) {
params := Parameters{ params := Parameters{
Parameters: snowball.Parameters{ Parameters: snowball.Parameters{
Metrics: prometheus.NewRegistry(), Metrics: prometheus.NewRegistry(),
K: 1, K: 1,
Alpha: 1, Alpha: 1,
BetaVirtuous: 1, BetaVirtuous: 1,
BetaRogue: 1, BetaRogue: 1,
ConcurrentRepolls: 1,
}, },
Parents: 2, Parents: 2,
BatchSize: 1, BatchSize: 1,
@ -660,11 +667,12 @@ func TestAvalancheQuiesce(t *testing.T) {
func TestAvalancheOrphans(t *testing.T) { func TestAvalancheOrphans(t *testing.T) {
params := Parameters{ params := Parameters{
Parameters: snowball.Parameters{ Parameters: snowball.Parameters{
Metrics: prometheus.NewRegistry(), Metrics: prometheus.NewRegistry(),
K: 1, K: 1,
Alpha: 1, Alpha: 1,
BetaVirtuous: math.MaxInt32, BetaVirtuous: math.MaxInt32,
BetaRogue: math.MaxInt32, BetaRogue: math.MaxInt32,
ConcurrentRepolls: 1,
}, },
Parents: 2, Parents: 2,
BatchSize: 1, BatchSize: 1,

View File

@ -0,0 +1,27 @@
// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package snowball
import (
"fmt"
)
// binarySlush is the implementation of a binary slush instance
type binarySlush struct {
// preference is the choice that last had a successful poll. Unless there
// hasn't been a successful poll, in which case it is the initially provided
// choice.
preference int
}
// Initialize implements the BinarySlush interface
func (sl *binarySlush) Initialize(choice int) { sl.preference = choice }
// Preference implements the BinarySlush interface
func (sl *binarySlush) Preference() int { return sl.preference }
// RecordSuccessfulPoll implements the BinarySlush interface
func (sl *binarySlush) RecordSuccessfulPoll(choice int) { sl.preference = choice }
func (sl *binarySlush) String() string { return fmt.Sprintf("SL(Preference = %d)", sl.preference) }

View File

@ -9,6 +9,9 @@ import (
// binarySnowball is the implementation of a binary snowball instance // binarySnowball is the implementation of a binary snowball instance
type binarySnowball struct { type binarySnowball struct {
// wrap the binary snowflake logic
binarySnowflake
// preference is the choice with the largest number of successful polls. // preference is the choice with the largest number of successful polls.
// Ties are broken by switching choice lazily // Ties are broken by switching choice lazily
preference int preference int
@ -16,15 +19,12 @@ type binarySnowball struct {
// numSuccessfulPolls tracks the total number of successful network polls of // numSuccessfulPolls tracks the total number of successful network polls of
// the 0 and 1 choices // the 0 and 1 choices
numSuccessfulPolls [2]int numSuccessfulPolls [2]int
// snowflake wraps the binary snowflake logic
snowflake binarySnowflake
} }
// Initialize implements the BinarySnowball interface // Initialize implements the BinarySnowball interface
func (sb *binarySnowball) Initialize(beta, choice int) { func (sb *binarySnowball) Initialize(beta, choice int) {
sb.binarySnowflake.Initialize(beta, choice)
sb.preference = choice sb.preference = choice
sb.snowflake.Initialize(beta, choice)
} }
// Preference implements the BinarySnowball interface // Preference implements the BinarySnowball interface
@ -34,7 +34,7 @@ func (sb *binarySnowball) Preference() int {
// this case is handled for completion. Therefore, if snowflake is // this case is handled for completion. Therefore, if snowflake is
// finalized, then our finalized snowflake choice should be preferred. // finalized, then our finalized snowflake choice should be preferred.
if sb.Finalized() { if sb.Finalized() {
return sb.snowflake.Preference() return sb.binarySnowflake.Preference()
} }
return sb.preference return sb.preference
} }
@ -45,20 +45,14 @@ func (sb *binarySnowball) RecordSuccessfulPoll(choice int) {
if sb.numSuccessfulPolls[choice] > sb.numSuccessfulPolls[1-choice] { if sb.numSuccessfulPolls[choice] > sb.numSuccessfulPolls[1-choice] {
sb.preference = choice sb.preference = choice
} }
sb.snowflake.RecordSuccessfulPoll(choice) sb.binarySnowflake.RecordSuccessfulPoll(choice)
} }
// RecordUnsuccessfulPoll implements the BinarySnowball interface
func (sb *binarySnowball) RecordUnsuccessfulPoll() { sb.snowflake.RecordUnsuccessfulPoll() }
// Finalized implements the BinarySnowball interface
func (sb *binarySnowball) Finalized() bool { return sb.snowflake.Finalized() }
func (sb *binarySnowball) String() string { func (sb *binarySnowball) String() string {
return fmt.Sprintf( return fmt.Sprintf(
"SB(Preference = %d, NumSuccessfulPolls[0] = %d, NumSuccessfulPolls[1] = %d, SF = %s)", "SB(Preference = %d, NumSuccessfulPolls[0] = %d, NumSuccessfulPolls[1] = %d, %s)",
sb.preference, sb.preference,
sb.numSuccessfulPolls[0], sb.numSuccessfulPolls[0],
sb.numSuccessfulPolls[1], sb.numSuccessfulPolls[1],
&sb.snowflake) &sb.binarySnowflake)
} }

View File

@ -96,15 +96,15 @@ func TestBinarySnowballRecordUnsuccessfulPoll(t *testing.T) {
t.Fatalf("Finalized too late") t.Fatalf("Finalized too late")
} }
expected := "SB(Preference = 1, NumSuccessfulPolls[0] = 0, NumSuccessfulPolls[1] = 3, SF = SF(Preference = 1, Confidence = 2, Finalized = true))" expected := "SB(Preference = 1, NumSuccessfulPolls[0] = 0, NumSuccessfulPolls[1] = 3, SF(Confidence = 2, Finalized = true, SL(Preference = 1)))"
if str := sb.String(); str != expected { if str := sb.String(); str != expected {
t.Fatalf("Wrong state. Expected:\n%s\nGot:\n%s", expected, str) t.Fatalf("Wrong state. Expected:\n%s\nGot:\n%s", expected, str)
} }
} }
func TestBinarySnowballAcceptWeirdColor(t *testing.T) { func TestBinarySnowballAcceptWeirdColor(t *testing.T) {
Red := 0 Blue := 0
Blue := 1 Red := 1
beta := 2 beta := 2
@ -151,7 +151,7 @@ func TestBinarySnowballAcceptWeirdColor(t *testing.T) {
t.Fatalf("Finalized too late") t.Fatalf("Finalized too late")
} }
expected := "SB(Preference = 0, NumSuccessfulPolls[0] = 2, NumSuccessfulPolls[1] = 2, SF = SF(Preference = 1, Confidence = 2, Finalized = true))" expected := "SB(Preference = 1, NumSuccessfulPolls[0] = 2, NumSuccessfulPolls[1] = 2, SF(Confidence = 2, Finalized = true, SL(Preference = 0)))"
if str := sb.String(); str != expected { if str := sb.String(); str != expected {
t.Fatalf("Wrong state. Expected:\n%s\nGot:\n%s", expected, str) t.Fatalf("Wrong state. Expected:\n%s\nGot:\n%s", expected, str)
} }
@ -190,7 +190,7 @@ func TestBinarySnowballLockColor(t *testing.T) {
t.Fatalf("Finalized too late") t.Fatalf("Finalized too late")
} }
expected := "SB(Preference = 1, NumSuccessfulPolls[0] = 1, NumSuccessfulPolls[1] = 2, SF = SF(Preference = 0, Confidence = 1, Finalized = true))" expected := "SB(Preference = 1, NumSuccessfulPolls[0] = 1, NumSuccessfulPolls[1] = 2, SF(Confidence = 1, Finalized = true, SL(Preference = 0)))"
if str := sb.String(); str != expected { if str := sb.String(); str != expected {
t.Fatalf("Wrong state. Expected:\n%s\nGot:\n%s", expected, str) t.Fatalf("Wrong state. Expected:\n%s\nGot:\n%s", expected, str)
} }

View File

@ -9,10 +9,8 @@ import (
// binarySnowflake is the implementation of a binary snowflake instance // binarySnowflake is the implementation of a binary snowflake instance
type binarySnowflake struct { type binarySnowflake struct {
// preference is the choice that last had a successful poll. Unless there // wrap the binary slush logic
// hasn't been a successful poll, in which case it is the initially provided binarySlush
// choice.
preference int
// confidence tracks the number of successful polls in a row that have // confidence tracks the number of successful polls in a row that have
// returned the preference // returned the preference
@ -29,29 +27,26 @@ type binarySnowflake struct {
// Initialize implements the BinarySnowflake interface // Initialize implements the BinarySnowflake interface
func (sf *binarySnowflake) Initialize(beta, choice int) { func (sf *binarySnowflake) Initialize(beta, choice int) {
sf.binarySlush.Initialize(choice)
sf.beta = beta sf.beta = beta
sf.preference = choice
} }
// Preference implements the BinarySnowflake interface
func (sf *binarySnowflake) Preference() int { return sf.preference }
// RecordSuccessfulPoll implements the BinarySnowflake interface // RecordSuccessfulPoll implements the BinarySnowflake interface
func (sf *binarySnowflake) RecordSuccessfulPoll(choice int) { func (sf *binarySnowflake) RecordSuccessfulPoll(choice int) {
if sf.Finalized() { if sf.finalized {
return // This instace is already decided. return // This instace is already decided.
} }
if sf.preference == choice { if preference := sf.Preference(); preference == choice {
sf.confidence++ sf.confidence++
} else { } else {
// confidence is set to 1 because there has already been 1 successful // confidence is set to 1 because there has already been 1 successful
// poll, namely this poll. // poll, namely this poll.
sf.confidence = 1 sf.confidence = 1
sf.preference = choice
} }
sf.finalized = sf.confidence >= sf.beta sf.finalized = sf.confidence >= sf.beta
sf.binarySlush.RecordSuccessfulPoll(choice)
} }
// RecordUnsuccessfulPoll implements the BinarySnowflake interface // RecordUnsuccessfulPoll implements the BinarySnowflake interface
@ -61,8 +56,8 @@ func (sf *binarySnowflake) RecordUnsuccessfulPoll() { sf.confidence = 0 }
func (sf *binarySnowflake) Finalized() bool { return sf.finalized } func (sf *binarySnowflake) Finalized() bool { return sf.finalized }
func (sf *binarySnowflake) String() string { func (sf *binarySnowflake) String() string {
return fmt.Sprintf("SF(Preference = %d, Confidence = %d, Finalized = %v)", return fmt.Sprintf("SF(Confidence = %d, Finalized = %v, %s)",
sf.Preference(),
sf.confidence, sf.confidence,
sf.Finalized()) sf.finalized,
&sf.binarySlush)
} }

View File

@ -0,0 +1,56 @@
// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package snowball
import (
"testing"
)
func TestBinarySnowflake(t *testing.T) {
Blue := 0
Red := 1
beta := 2
sf := binarySnowflake{}
sf.Initialize(beta, Red)
if pref := sf.Preference(); pref != Red {
t.Fatalf("Wrong preference. Expected %d got %d", Red, pref)
} else if sf.Finalized() {
t.Fatalf("Finalized too early")
}
sf.RecordSuccessfulPoll(Blue)
if pref := sf.Preference(); pref != Blue {
t.Fatalf("Wrong preference. Expected %d got %d", Blue, pref)
} else if sf.Finalized() {
t.Fatalf("Finalized too early")
}
sf.RecordSuccessfulPoll(Red)
if pref := sf.Preference(); pref != Red {
t.Fatalf("Wrong preference. Expected %d got %d", Red, pref)
} else if sf.Finalized() {
t.Fatalf("Finalized too early")
}
sf.RecordSuccessfulPoll(Blue)
if pref := sf.Preference(); pref != Blue {
t.Fatalf("Wrong preference. Expected %d got %d", Blue, pref)
} else if sf.Finalized() {
t.Fatalf("Finalized too early")
}
sf.RecordSuccessfulPoll(Blue)
if pref := sf.Preference(); pref != Blue {
t.Fatalf("Wrong preference. Expected %d got %d", Blue, pref)
} else if !sf.Finalized() {
t.Fatalf("Didn't finalized correctly")
}
}

View File

@ -24,6 +24,7 @@ type Byzantine struct {
// Initialize implements the Consensus interface // Initialize implements the Consensus interface
func (b *Byzantine) Initialize(params Parameters, choice ids.ID) { func (b *Byzantine) Initialize(params Parameters, choice ids.ID) {
b.params = params
b.preference = choice b.preference = choice
} }

View File

@ -0,0 +1,54 @@
// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package snowball
import (
"testing"
"github.com/ava-labs/gecko/ids"
"github.com/prometheus/client_golang/prometheus"
)
func TestByzantine(t *testing.T) {
params := Parameters{
Metrics: prometheus.NewRegistry(),
K: 1, Alpha: 1, BetaVirtuous: 3, BetaRogue: 5,
}
byzFactory := ByzantineFactory{}
byz := byzFactory.New()
byz.Initialize(params, Blue)
if ret := byz.Parameters(); ret != params {
t.Fatalf("Should have returned the correct params")
}
byz.Add(Green)
if pref := byz.Preference(); !pref.Equals(Blue) {
t.Fatalf("Wrong preference, expected %s returned %s", Blue, pref)
}
oneGreen := ids.Bag{}
oneGreen.Add(Green)
byz.RecordPoll(oneGreen)
if pref := byz.Preference(); !pref.Equals(Blue) {
t.Fatalf("Wrong preference, expected %s returned %s", Blue, pref)
}
byz.RecordUnsuccessfulPoll()
if pref := byz.Preference(); !pref.Equals(Blue) {
t.Fatalf("Wrong preference, expected %s returned %s", Blue, pref)
}
if final := byz.Finalized(); !final {
t.Fatalf("Should be marked as accepted")
}
if str := byz.String(); str != Blue.String() {
t.Fatalf("Wrong string, expected %s returned %s", Blue, str)
}
}

View File

@ -69,6 +69,23 @@ type NnarySnowflake interface {
Finalized() bool Finalized() bool
} }
// NnarySlush is a slush instance deciding between an unbounded number of
// values. After performing a network sample of k nodes, if you have alpha
// votes for one of the choices, you should vote for that choice.
type NnarySlush interface {
fmt.Stringer
// Takes in the initial choice
Initialize(initialPreference ids.ID)
// Returns the currently preferred choice to be finalized
Preference() ids.ID
// RecordSuccessfulPoll records a successful poll towards finalizing the
// specified choice. Assumes the choice was previously added.
RecordSuccessfulPoll(choice ids.ID)
}
// BinarySnowball augments BinarySnowflake with a counter that tracks the total // BinarySnowball augments BinarySnowflake with a counter that tracks the total
// number of positive responses from a network sample. // number of positive responses from a network sample.
type BinarySnowball interface{ BinarySnowflake } type BinarySnowball interface{ BinarySnowflake }
@ -97,6 +114,23 @@ type BinarySnowflake interface {
Finalized() bool Finalized() bool
} }
// BinarySlush is a slush instance deciding between two values. After performing
// a network sample of k nodes, if you have alpha votes for one of the choices,
// you should vote for that choice.
type BinarySlush interface {
fmt.Stringer
// Takes in the initial choice
Initialize(initialPreference int)
// Returns the currently preferred choice to be finalized
Preference() int
// RecordSuccessfulPoll records a successful poll towards finalizing the
// specified choice
RecordSuccessfulPoll(choice int)
}
// UnarySnowball is a snowball instance deciding on one value. After performing // UnarySnowball is a snowball instance deciding on one value. After performing
// a network sample of k nodes, if you have alpha votes for the choice, you // a network sample of k nodes, if you have alpha votes for the choice, you
// should vote. Otherwise, you should reset. // should vote. Otherwise, you should reset.
@ -122,3 +156,29 @@ type UnarySnowball interface {
// Returns a new unary snowball instance with the same state // Returns a new unary snowball instance with the same state
Clone() UnarySnowball Clone() UnarySnowball
} }
// UnarySnowflake is a snowflake instance deciding on one value. After
// performing a network sample of k nodes, if you have alpha votes for the
// choice, you should vote. Otherwise, you should reset.
type UnarySnowflake interface {
fmt.Stringer
// Takes in the beta value
Initialize(beta int)
// RecordSuccessfulPoll records a successful poll towards finalizing
RecordSuccessfulPoll()
// RecordUnsuccessfulPoll resets the snowflake counter of this instance
RecordUnsuccessfulPoll()
// Return whether a choice has been finalized
Finalized() bool
// Returns a new binary snowball instance with the agreement parameters
// transferred. Takes in the new beta value and the original choice
Extend(beta, originalPreference int) BinarySnowflake
// Returns a new unary snowflake instance with the same state
Clone() UnarySnowflake
}

View File

@ -22,7 +22,7 @@ func ParamsTest(t *testing.T, factory Factory) {
params := Parameters{ params := Parameters{
Metrics: prometheus.NewRegistry(), Metrics: prometheus.NewRegistry(),
K: 2, Alpha: 2, BetaVirtuous: 1, BetaRogue: 2, K: 2, Alpha: 2, BetaVirtuous: 1, BetaRogue: 2, ConcurrentRepolls: 1,
} }
sb.Initialize(params, Red) sb.Initialize(params, Red)
@ -34,5 +34,7 @@ func ParamsTest(t *testing.T, factory Factory) {
t.Fatalf("Wrong Beta1 parameter") t.Fatalf("Wrong Beta1 parameter")
} else if p.BetaRogue != params.BetaRogue { } else if p.BetaRogue != params.BetaRogue {
t.Fatalf("Wrong Beta2 parameter") t.Fatalf("Wrong Beta2 parameter")
} else if p.ConcurrentRepolls != params.ConcurrentRepolls {
t.Fatalf("Wrong Repoll parameter")
} }
} }

View File

@ -15,40 +15,27 @@ func (FlatFactory) New() Consensus { return &Flat{} }
// Flat is a naive implementation of a multi-choice snowball instance // Flat is a naive implementation of a multi-choice snowball instance
type Flat struct { type Flat struct {
// wraps the n-nary snowball logic
nnarySnowball
// params contains all the configurations of a snowball instance // params contains all the configurations of a snowball instance
params Parameters params Parameters
// snowball wraps the n-nary snowball logic
snowball nnarySnowball
} }
// Initialize implements the Consensus interface // Initialize implements the Consensus interface
func (f *Flat) Initialize(params Parameters, choice ids.ID) { func (f *Flat) Initialize(params Parameters, choice ids.ID) {
f.nnarySnowball.Initialize(params.BetaVirtuous, params.BetaRogue, choice)
f.params = params f.params = params
f.snowball.Initialize(params.BetaVirtuous, params.BetaRogue, choice)
} }
// Parameters implements the Consensus interface // Parameters implements the Consensus interface
func (f *Flat) Parameters() Parameters { return f.params } func (f *Flat) Parameters() Parameters { return f.params }
// Add implements the Consensus interface
func (f *Flat) Add(choice ids.ID) { f.snowball.Add(choice) }
// Preference implements the Consensus interface
func (f *Flat) Preference() ids.ID { return f.snowball.Preference() }
// RecordPoll implements the Consensus interface // RecordPoll implements the Consensus interface
func (f *Flat) RecordPoll(votes ids.Bag) { func (f *Flat) RecordPoll(votes ids.Bag) {
if pollMode, numVotes := votes.Mode(); numVotes >= f.params.Alpha { if pollMode, numVotes := votes.Mode(); numVotes >= f.params.Alpha {
f.snowball.RecordSuccessfulPoll(pollMode) f.nnarySnowball.RecordSuccessfulPoll(pollMode)
} else { } else {
f.RecordUnsuccessfulPoll() f.RecordUnsuccessfulPoll()
} }
} }
// RecordUnsuccessfulPoll implements the Consensus interface
func (f *Flat) RecordUnsuccessfulPoll() { f.snowball.RecordUnsuccessfulPoll() }
// Finalized implements the Consensus interface
func (f *Flat) Finalized() bool { return f.snowball.Finalized() }
func (f *Flat) String() string { return f.snowball.String() }

View File

@ -65,7 +65,7 @@ func TestFlat(t *testing.T) {
t.Fatalf("Finalized too late") t.Fatalf("Finalized too late")
} }
expected := "SB(Preference = TtF4d2QWbk5vzQGTEPrN48x6vwgAoAmKQ9cbp79inpQmcRKES, NumSuccessfulPolls = 3, SF = SF(Preference = TtF4d2QWbk5vzQGTEPrN48x6vwgAoAmKQ9cbp79inpQmcRKES, Confidence = 2, Finalized = true))" expected := "SB(Preference = TtF4d2QWbk5vzQGTEPrN48x6vwgAoAmKQ9cbp79inpQmcRKES, NumSuccessfulPolls = 3, SF(Confidence = 2, Finalized = true, SL(Preference = TtF4d2QWbk5vzQGTEPrN48x6vwgAoAmKQ9cbp79inpQmcRKES)))"
if str := f.String(); str != expected { if str := f.String(); str != expected {
t.Fatalf("Wrong state. Expected:\n%s\nGot:\n%s", expected, str) t.Fatalf("Wrong state. Expected:\n%s\nGot:\n%s", expected, str)
} }

View File

@ -0,0 +1,30 @@
// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package snowball
import (
"fmt"
"github.com/ava-labs/gecko/ids"
)
// nnarySlush is the implementation of a slush instance with an unbounded number
// of choices
type nnarySlush struct {
// preference is the choice that last had a successful poll. Unless there
// hasn't been a successful poll, in which case it is the initially provided
// choice.
preference ids.ID
}
// Initialize implements the NnarySlush interface
func (sl *nnarySlush) Initialize(choice ids.ID) { sl.preference = choice }
// Preference implements the NnarySlush interface
func (sl *nnarySlush) Preference() ids.ID { return sl.preference }
// RecordSuccessfulPoll implements the NnarySlush interface
func (sl *nnarySlush) RecordSuccessfulPoll(choice ids.ID) { sl.preference = choice }
func (sl *nnarySlush) String() string { return fmt.Sprintf("SL(Preference = %s)", sl.preference) }

View File

@ -11,6 +11,9 @@ import (
// nnarySnowball is a naive implementation of a multi-color snowball instance // nnarySnowball is a naive implementation of a multi-color snowball instance
type nnarySnowball struct { type nnarySnowball struct {
// wrap the n-nary snowflake logic
nnarySnowflake
// preference is the choice with the largest number of successful polls. // preference is the choice with the largest number of successful polls.
// Ties are broken by switching choice lazily // Ties are broken by switching choice lazily
preference ids.ID preference ids.ID
@ -22,21 +25,15 @@ type nnarySnowball struct {
// numSuccessfulPolls tracks the total number of successful network polls of // numSuccessfulPolls tracks the total number of successful network polls of
// the choices // the choices
numSuccessfulPolls map[[32]byte]int numSuccessfulPolls map[[32]byte]int
// snowflake wraps the n-nary snowflake logic
snowflake nnarySnowflake
} }
// Initialize implements the NnarySnowball interface // Initialize implements the NnarySnowball interface
func (sb *nnarySnowball) Initialize(betaVirtuous, betaRogue int, choice ids.ID) { func (sb *nnarySnowball) Initialize(betaVirtuous, betaRogue int, choice ids.ID) {
sb.nnarySnowflake.Initialize(betaVirtuous, betaRogue, choice)
sb.preference = choice sb.preference = choice
sb.numSuccessfulPolls = make(map[[32]byte]int) sb.numSuccessfulPolls = make(map[[32]byte]int)
sb.snowflake.Initialize(betaVirtuous, betaRogue, choice)
} }
// Add implements the NnarySnowball interface
func (sb *nnarySnowball) Add(choice ids.ID) { sb.snowflake.Add(choice) }
// Preference implements the NnarySnowball interface // Preference implements the NnarySnowball interface
func (sb *nnarySnowball) Preference() ids.ID { func (sb *nnarySnowball) Preference() ids.ID {
// It is possible, with low probability, that the snowflake preference is // It is possible, with low probability, that the snowflake preference is
@ -44,17 +41,13 @@ func (sb *nnarySnowball) Preference() ids.ID {
// this case is handled for completion. Therefore, if snowflake is // this case is handled for completion. Therefore, if snowflake is
// finalized, then our finalized snowflake choice should be preferred. // finalized, then our finalized snowflake choice should be preferred.
if sb.Finalized() { if sb.Finalized() {
return sb.snowflake.Preference() return sb.nnarySnowflake.Preference()
} }
return sb.preference return sb.preference
} }
// RecordSuccessfulPoll implements the NnarySnowball interface // RecordSuccessfulPoll implements the NnarySnowball interface
func (sb *nnarySnowball) RecordSuccessfulPoll(choice ids.ID) { func (sb *nnarySnowball) RecordSuccessfulPoll(choice ids.ID) {
if sb.Finalized() {
return
}
key := choice.Key() key := choice.Key()
numSuccessfulPolls := sb.numSuccessfulPolls[key] + 1 numSuccessfulPolls := sb.numSuccessfulPolls[key] + 1
sb.numSuccessfulPolls[key] = numSuccessfulPolls sb.numSuccessfulPolls[key] = numSuccessfulPolls
@ -64,16 +57,10 @@ func (sb *nnarySnowball) RecordSuccessfulPoll(choice ids.ID) {
sb.maxSuccessfulPolls = numSuccessfulPolls sb.maxSuccessfulPolls = numSuccessfulPolls
} }
sb.snowflake.RecordSuccessfulPoll(choice) sb.nnarySnowflake.RecordSuccessfulPoll(choice)
} }
// RecordUnsuccessfulPoll implements the NnarySnowball interface
func (sb *nnarySnowball) RecordUnsuccessfulPoll() { sb.snowflake.RecordUnsuccessfulPoll() }
// Finalized implements the NnarySnowball interface
func (sb *nnarySnowball) Finalized() bool { return sb.snowflake.Finalized() }
func (sb *nnarySnowball) String() string { func (sb *nnarySnowball) String() string {
return fmt.Sprintf("SB(Preference = %s, NumSuccessfulPolls = %d, SF = %s)", return fmt.Sprintf("SB(Preference = %s, NumSuccessfulPolls = %d, %s)",
sb.preference, sb.maxSuccessfulPolls, &sb.snowflake) sb.preference, sb.maxSuccessfulPolls, &sb.nnarySnowflake)
} }

View File

@ -55,50 +55,24 @@ func TestNnarySnowball(t *testing.T) {
} }
} }
func TestNnarySnowflake(t *testing.T) { func TestVirtuousNnarySnowball(t *testing.T) {
betaVirtuous := 2 betaVirtuous := 1
betaRogue := 2 betaRogue := 2
sf := nnarySnowflake{} sb := nnarySnowball{}
sf.Initialize(betaVirtuous, betaRogue, Red) sb.Initialize(betaVirtuous, betaRogue, Red)
sf.Add(Blue)
sf.Add(Green)
if pref := sf.Preference(); !Red.Equals(pref) { if pref := sb.Preference(); !Red.Equals(pref) {
t.Fatalf("Wrong preference. Expected %s got %s", Red, pref) t.Fatalf("Wrong preference. Expected %s got %s", Red, pref)
} else if sf.Finalized() { } else if sb.Finalized() {
t.Fatalf("Finalized too early") t.Fatalf("Finalized too early")
} }
sf.RecordSuccessfulPoll(Blue) sb.RecordSuccessfulPoll(Red)
if pref := sf.Preference(); !Blue.Equals(pref) { if pref := sb.Preference(); !Red.Equals(pref) {
t.Fatalf("Wrong preference. Expected %s got %s", Blue, pref)
} else if sf.Finalized() {
t.Fatalf("Finalized too early")
}
sf.RecordSuccessfulPoll(Red)
if pref := sf.Preference(); !Red.Equals(pref) {
t.Fatalf("Wrong preference. Expected %s got %s", Red, pref) t.Fatalf("Wrong preference. Expected %s got %s", Red, pref)
} else if sf.Finalized() { } else if !sb.Finalized() {
t.Fatalf("Finalized too early")
}
sf.RecordSuccessfulPoll(Red)
if pref := sf.Preference(); !Red.Equals(pref) {
t.Fatalf("Wrong preference. Expected %s got %s", Red, pref)
} else if !sf.Finalized() {
t.Fatalf("Should be finalized")
}
sf.RecordSuccessfulPoll(Blue)
if pref := sf.Preference(); !Red.Equals(pref) {
t.Fatalf("Wrong preference. Expected %s got %s", Red, pref)
} else if !sf.Finalized() {
t.Fatalf("Should be finalized") t.Fatalf("Should be finalized")
} }
} }
@ -143,7 +117,7 @@ func TestNarySnowballRecordUnsuccessfulPoll(t *testing.T) {
t.Fatalf("Finalized too late") t.Fatalf("Finalized too late")
} }
expected := "SB(Preference = TtF4d2QWbk5vzQGTEPrN48x6vwgAoAmKQ9cbp79inpQmcRKES, NumSuccessfulPolls = 3, SF = SF(Preference = TtF4d2QWbk5vzQGTEPrN48x6vwgAoAmKQ9cbp79inpQmcRKES, Confidence = 2, Finalized = true))" expected := "SB(Preference = TtF4d2QWbk5vzQGTEPrN48x6vwgAoAmKQ9cbp79inpQmcRKES, NumSuccessfulPolls = 3, SF(Confidence = 2, Finalized = true, SL(Preference = TtF4d2QWbk5vzQGTEPrN48x6vwgAoAmKQ9cbp79inpQmcRKES)))"
if str := sb.String(); str != expected { if str := sb.String(); str != expected {
t.Fatalf("Wrong state. Expected:\n%s\nGot:\n%s", expected, str) t.Fatalf("Wrong state. Expected:\n%s\nGot:\n%s", expected, str)
} }
@ -159,7 +133,7 @@ func TestNarySnowballRecordUnsuccessfulPoll(t *testing.T) {
} }
} }
func TestNarySnowflakeColor(t *testing.T) { func TestNarySnowballDifferentSnowflakeColor(t *testing.T) {
betaVirtuous := 2 betaVirtuous := 2
betaRogue := 2 betaRogue := 2
@ -175,7 +149,7 @@ func TestNarySnowflakeColor(t *testing.T) {
sb.RecordSuccessfulPoll(Blue) sb.RecordSuccessfulPoll(Blue)
if pref := sb.snowflake.Preference(); !Blue.Equals(pref) { if pref := sb.nnarySnowflake.Preference(); !Blue.Equals(pref) {
t.Fatalf("Wrong preference. Expected %s got %s", Blue, pref) t.Fatalf("Wrong preference. Expected %s got %s", Blue, pref)
} }
@ -183,7 +157,7 @@ func TestNarySnowflakeColor(t *testing.T) {
if pref := sb.Preference(); !Blue.Equals(pref) { if pref := sb.Preference(); !Blue.Equals(pref) {
t.Fatalf("Wrong preference. Expected %s got %s", Blue, pref) t.Fatalf("Wrong preference. Expected %s got %s", Blue, pref)
} else if pref := sb.snowflake.Preference(); !Red.Equals(pref) { } else if pref := sb.nnarySnowflake.Preference(); !Red.Equals(pref) {
t.Fatalf("Wrong preference. Expected %s got %s", Blue, pref) t.Fatalf("Wrong preference. Expected %s got %s", Blue, pref)
} }
} }

View File

@ -12,6 +12,9 @@ import (
// nnarySnowflake is the implementation of a snowflake instance with an // nnarySnowflake is the implementation of a snowflake instance with an
// unbounded number of choices // unbounded number of choices
type nnarySnowflake struct { type nnarySnowflake struct {
// wrap the n-nary slush logic
nnarySlush
// betaVirtuous is the number of consecutive successful queries required for // betaVirtuous is the number of consecutive successful queries required for
// finalization on a virtuous instance. // finalization on a virtuous instance.
betaVirtuous int betaVirtuous int
@ -24,11 +27,6 @@ type nnarySnowflake struct {
// returned the preference // returned the preference
confidence int confidence int
// preference is the choice that last had a successful poll. Unless there
// hasn't been a successful poll, in which case it is the initially provided
// choice.
preference ids.ID
// rogue tracks if this instance has multiple choices or only one // rogue tracks if this instance has multiple choices or only one
rogue bool rogue bool
@ -39,32 +37,31 @@ type nnarySnowflake struct {
// Initialize implements the NnarySnowflake interface // Initialize implements the NnarySnowflake interface
func (sf *nnarySnowflake) Initialize(betaVirtuous, betaRogue int, choice ids.ID) { func (sf *nnarySnowflake) Initialize(betaVirtuous, betaRogue int, choice ids.ID) {
sf.nnarySlush.Initialize(choice)
sf.betaVirtuous = betaVirtuous sf.betaVirtuous = betaVirtuous
sf.betaRogue = betaRogue sf.betaRogue = betaRogue
sf.preference = choice
} }
// Add implements the NnarySnowflake interface // Add implements the NnarySnowflake interface
func (sf *nnarySnowflake) Add(choice ids.ID) { sf.rogue = sf.rogue || !choice.Equals(sf.preference) } func (sf *nnarySnowflake) Add(choice ids.ID) { sf.rogue = sf.rogue || !choice.Equals(sf.preference) }
// Preference implements the NnarySnowflake interface
func (sf *nnarySnowflake) Preference() ids.ID { return sf.preference }
// RecordSuccessfulPoll implements the NnarySnowflake interface // RecordSuccessfulPoll implements the NnarySnowflake interface
func (sf *nnarySnowflake) RecordSuccessfulPoll(choice ids.ID) { func (sf *nnarySnowflake) RecordSuccessfulPoll(choice ids.ID) {
if sf.Finalized() { if sf.finalized {
return return // This instace is already decided.
} }
if sf.preference.Equals(choice) { if preference := sf.nnarySlush.Preference(); preference.Equals(choice) {
sf.confidence++ sf.confidence++
} else { } else {
// confidence is set to 1 because there has already been 1 successful
// poll, namely this poll.
sf.confidence = 1 sf.confidence = 1
sf.preference = choice
} }
sf.finalized = (!sf.rogue && sf.confidence >= sf.betaVirtuous) || sf.finalized = (!sf.rogue && sf.confidence >= sf.betaVirtuous) ||
sf.confidence >= sf.betaRogue sf.confidence >= sf.betaRogue
sf.nnarySlush.RecordSuccessfulPoll(choice)
} }
// RecordUnsuccessfulPoll implements the NnarySnowflake interface // RecordUnsuccessfulPoll implements the NnarySnowflake interface
@ -74,8 +71,8 @@ func (sf *nnarySnowflake) RecordUnsuccessfulPoll() { sf.confidence = 0 }
func (sf *nnarySnowflake) Finalized() bool { return sf.finalized } func (sf *nnarySnowflake) Finalized() bool { return sf.finalized }
func (sf *nnarySnowflake) String() string { func (sf *nnarySnowflake) String() string {
return fmt.Sprintf("SF(Preference = %s, Confidence = %d, Finalized = %v)", return fmt.Sprintf("SF(Confidence = %d, Finalized = %v, %s)",
sf.preference,
sf.confidence, sf.confidence,
sf.Finalized()) sf.finalized,
&sf.nnarySlush)
} }

View File

@ -0,0 +1,134 @@
// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package snowball
import (
"testing"
)
func TestNnarySnowflake(t *testing.T) {
betaVirtuous := 2
betaRogue := 2
sf := nnarySnowflake{}
sf.Initialize(betaVirtuous, betaRogue, Red)
sf.Add(Blue)
sf.Add(Green)
if pref := sf.Preference(); !Red.Equals(pref) {
t.Fatalf("Wrong preference. Expected %s got %s", Red, pref)
} else if sf.Finalized() {
t.Fatalf("Finalized too early")
}
sf.RecordSuccessfulPoll(Blue)
if pref := sf.Preference(); !Blue.Equals(pref) {
t.Fatalf("Wrong preference. Expected %s got %s", Blue, pref)
} else if sf.Finalized() {
t.Fatalf("Finalized too early")
}
sf.RecordSuccessfulPoll(Red)
if pref := sf.Preference(); !Red.Equals(pref) {
t.Fatalf("Wrong preference. Expected %s got %s", Red, pref)
} else if sf.Finalized() {
t.Fatalf("Finalized too early")
}
sf.RecordSuccessfulPoll(Red)
if pref := sf.Preference(); !Red.Equals(pref) {
t.Fatalf("Wrong preference. Expected %s got %s", Red, pref)
} else if !sf.Finalized() {
t.Fatalf("Should be finalized")
}
sf.RecordSuccessfulPoll(Blue)
if pref := sf.Preference(); !Red.Equals(pref) {
t.Fatalf("Wrong preference. Expected %s got %s", Red, pref)
} else if !sf.Finalized() {
t.Fatalf("Should be finalized")
}
}
func TestVirtuousNnarySnowflake(t *testing.T) {
betaVirtuous := 2
betaRogue := 3
sb := nnarySnowflake{}
sb.Initialize(betaVirtuous, betaRogue, Red)
if pref := sb.Preference(); !Red.Equals(pref) {
t.Fatalf("Wrong preference. Expected %s got %s", Red, pref)
} else if sb.Finalized() {
t.Fatalf("Finalized too early")
}
sb.RecordSuccessfulPoll(Red)
if pref := sb.Preference(); !Red.Equals(pref) {
t.Fatalf("Wrong preference. Expected %s got %s", Red, pref)
} else if sb.Finalized() {
t.Fatalf("Finalized too early")
}
sb.RecordSuccessfulPoll(Red)
if pref := sb.Preference(); !Red.Equals(pref) {
t.Fatalf("Wrong preference. Expected %s got %s", Red, pref)
} else if !sb.Finalized() {
t.Fatalf("Should be finalized")
}
}
func TestRogueNnarySnowflake(t *testing.T) {
betaVirtuous := 1
betaRogue := 2
sb := nnarySnowflake{}
sb.Initialize(betaVirtuous, betaRogue, Red)
if sb.rogue {
t.Fatalf("Shouldn't be rogue")
}
sb.Add(Red)
if sb.rogue {
t.Fatalf("Shouldn't be rogue")
}
sb.Add(Blue)
if !sb.rogue {
t.Fatalf("Should be rogue")
}
sb.Add(Red)
if !sb.rogue {
t.Fatalf("Should be rogue")
}
if pref := sb.Preference(); !Red.Equals(pref) {
t.Fatalf("Wrong preference. Expected %s got %s", Red, pref)
} else if sb.Finalized() {
t.Fatalf("Finalized too early")
}
sb.RecordSuccessfulPoll(Red)
if pref := sb.Preference(); !Red.Equals(pref) {
t.Fatalf("Wrong preference. Expected %s got %s", Red, pref)
} else if sb.Finalized() {
t.Fatalf("Finalized too early")
}
sb.RecordSuccessfulPoll(Red)
if pref := sb.Preference(); !Red.Equals(pref) {
t.Fatalf("Wrong preference. Expected %s got %s", Red, pref)
} else if !sb.Finalized() {
t.Fatalf("Should be finalized")
}
}

View File

@ -9,11 +9,28 @@ import (
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
) )
const (
errMsg = "__________ .___\n" +
"\\______ \\____________ __| _/__.__.\n" +
" | | _/\\_ __ \\__ \\ / __ < | |\n" +
" | | \\ | | \\// __ \\_/ /_/ |\\___ |\n" +
" |______ / |__| (____ /\\____ |/ ____|\n" +
" \\/ \\/ \\/\\/\n" +
"\n" +
"🏆 🏆 🏆 🏆 🏆 🏆\n" +
" ________ ________ ________________\n" +
" / _____/ \\_____ \\ / _ \\__ ___/\n" +
"/ \\ ___ / | \\ / /_\\ \\| |\n" +
"\\ \\_\\ \\/ | \\/ | \\ |\n" +
" \\______ /\\_______ /\\____|__ /____|\n" +
" \\/ \\/ \\/\n"
)
// Parameters required for snowball consensus // Parameters required for snowball consensus
type Parameters struct { type Parameters struct {
Namespace string Namespace string
Metrics prometheus.Registerer Metrics prometheus.Registerer
K, Alpha, BetaVirtuous, BetaRogue int K, Alpha, BetaVirtuous, BetaRogue, ConcurrentRepolls int
} }
// Valid returns nil if the parameters describe a valid initialization. // Valid returns nil if the parameters describe a valid initialization.
@ -25,8 +42,14 @@ func (p Parameters) Valid() error {
return fmt.Errorf("K = %d, Alpha = %d: Fails the condition that: Alpha <= K", p.K, p.Alpha) return fmt.Errorf("K = %d, Alpha = %d: Fails the condition that: Alpha <= K", p.K, p.Alpha)
case p.BetaVirtuous <= 0: case p.BetaVirtuous <= 0:
return fmt.Errorf("BetaVirtuous = %d: Fails the condition that: 0 < BetaVirtuous", p.BetaVirtuous) return fmt.Errorf("BetaVirtuous = %d: Fails the condition that: 0 < BetaVirtuous", p.BetaVirtuous)
case p.BetaRogue == 3 && p.BetaVirtuous == 28:
return fmt.Errorf("BetaVirtuous = %d, BetaRogue = %d: Fails the condition that: BetaVirtuous <= BetaRogue\n%s", p.BetaVirtuous, p.BetaRogue, errMsg)
case p.BetaRogue < p.BetaVirtuous: case p.BetaRogue < p.BetaVirtuous:
return fmt.Errorf("BetaVirtuous = %d, BetaRogue = %d: Fails the condition that: BetaVirtuous <= BetaRogue", p.BetaVirtuous, p.BetaRogue) return fmt.Errorf("BetaVirtuous = %d, BetaRogue = %d: Fails the condition that: BetaVirtuous <= BetaRogue", p.BetaVirtuous, p.BetaRogue)
case p.ConcurrentRepolls <= 0:
return fmt.Errorf("ConcurrentRepolls = %d: Fails the condition that: 0 < ConcurrentRepolls", p.ConcurrentRepolls)
case p.ConcurrentRepolls > p.BetaRogue:
return fmt.Errorf("ConcurrentRepolls = %d, BetaRogue = %d: Fails the condition that: ConcurrentRepolls <= BetaRogue", p.ConcurrentRepolls, p.BetaRogue)
default: default:
return nil return nil
} }

Some files were not shown because too many files have changed in this diff Show More