Merge branch 'master' of github.com:ava-labs/gecko-internal

This commit is contained in:
Dan Laine 2020-06-22 09:45:26 -04:00
commit a20a54af4e
27 changed files with 574 additions and 181 deletions

View File

@ -10,129 +10,35 @@ import (
"github.com/ava-labs/gecko/api"
"github.com/ava-labs/gecko/chains"
"github.com/ava-labs/gecko/genesis"
"github.com/ava-labs/gecko/ids"
"github.com/ava-labs/gecko/network"
"github.com/ava-labs/gecko/snow/engine/common"
"github.com/ava-labs/gecko/utils/logging"
"github.com/ava-labs/gecko/version"
cjson "github.com/ava-labs/gecko/utils/json"
)
// Admin is the API service for node admin management
type Admin struct {
version version.Version
nodeID ids.ShortID
networkID uint32
log logging.Logger
networking network.Network
performance Performance
chainManager chains.Manager
httpServer *api.Server
}
// NewService returns a new admin API service
func NewService(version version.Version, nodeID ids.ShortID, networkID uint32, log logging.Logger, chainManager chains.Manager, peers network.Network, httpServer *api.Server) *common.HTTPHandler {
func NewService(log logging.Logger, chainManager chains.Manager, peers network.Network, httpServer *api.Server) *common.HTTPHandler {
newServer := rpc.NewServer()
codec := cjson.NewCodec()
newServer.RegisterCodec(codec, "application/json")
newServer.RegisterCodec(codec, "application/json;charset=UTF-8")
newServer.RegisterService(&Admin{
version: version,
nodeID: nodeID,
networkID: networkID,
log: log,
chainManager: chainManager,
networking: peers,
httpServer: httpServer,
}, "admin")
return &common.HTTPHandler{Handler: newServer}
}
// GetNodeVersionReply are the results from calling GetNodeVersion
type GetNodeVersionReply struct {
Version string `json:"version"`
}
// GetNodeVersion returns the version this node is running
func (service *Admin) GetNodeVersion(_ *http.Request, _ *struct{}, reply *GetNodeVersionReply) error {
service.log.Info("Admin: GetNodeVersion called")
reply.Version = service.version.String()
return nil
}
// GetNodeIDReply are the results from calling GetNodeID
type GetNodeIDReply struct {
NodeID ids.ShortID `json:"nodeID"`
}
// GetNodeID returns the node ID of this node
func (service *Admin) GetNodeID(_ *http.Request, _ *struct{}, reply *GetNodeIDReply) error {
service.log.Info("Admin: GetNodeID called")
reply.NodeID = service.nodeID
return nil
}
// GetNetworkIDReply are the results from calling GetNetworkID
type GetNetworkIDReply struct {
NetworkID cjson.Uint32 `json:"networkID"`
}
// GetNetworkID returns the network ID this node is running on
func (service *Admin) GetNetworkID(_ *http.Request, _ *struct{}, reply *GetNetworkIDReply) error {
service.log.Info("Admin: GetNetworkID called")
reply.NetworkID = cjson.Uint32(service.networkID)
return nil
}
// GetNetworkNameReply is the result from calling GetNetworkName
type GetNetworkNameReply struct {
NetworkName string `json:"networkName"`
}
// GetNetworkName returns the network name this node is running on
func (service *Admin) GetNetworkName(_ *http.Request, _ *struct{}, reply *GetNetworkNameReply) error {
service.log.Info("Admin: GetNetworkName called")
reply.NetworkName = genesis.NetworkName(service.networkID)
return nil
}
// GetBlockchainIDArgs are the arguments for calling GetBlockchainID
type GetBlockchainIDArgs struct {
Alias string `json:"alias"`
}
// GetBlockchainIDReply are the results from calling GetBlockchainID
type GetBlockchainIDReply struct {
BlockchainID string `json:"blockchainID"`
}
// GetBlockchainID returns the blockchain ID that resolves the alias that was supplied
func (service *Admin) GetBlockchainID(_ *http.Request, args *GetBlockchainIDArgs, reply *GetBlockchainIDReply) error {
service.log.Info("Admin: GetBlockchainID called")
bID, err := service.chainManager.Lookup(args.Alias)
reply.BlockchainID = bID.String()
return err
}
// PeersReply are the results from calling Peers
type PeersReply struct {
Peers []network.PeerID `json:"peers"`
}
// Peers returns the list of current validators
func (service *Admin) Peers(_ *http.Request, _ *struct{}, reply *PeersReply) error {
service.log.Info("Admin: Peers called")
reply.Peers = service.networking.Peers()
return nil
}
// StartCPUProfilerArgs are the arguments for calling StartCPUProfiler
type StartCPUProfilerArgs struct {
Filename string `json:"filename"`

View File

@ -7,11 +7,13 @@ import (
"net/http"
"time"
"github.com/AppsFlyer/go-sundheit"
health "github.com/AppsFlyer/go-sundheit"
"github.com/gorilla/rpc/v2"
"github.com/ava-labs/gecko/snow/engine/common"
"github.com/ava-labs/gecko/utils/json"
"github.com/ava-labs/gecko/utils/logging"
"github.com/gorilla/rpc/v2"
)
// defaultCheckOpts is a Check whose properties represent a default Check

131
api/info/service.go Normal file
View File

@ -0,0 +1,131 @@
// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package info
import (
"net/http"
"github.com/gorilla/rpc/v2"
"github.com/ava-labs/gecko/chains"
"github.com/ava-labs/gecko/genesis"
"github.com/ava-labs/gecko/ids"
"github.com/ava-labs/gecko/network"
"github.com/ava-labs/gecko/snow/engine/common"
"github.com/ava-labs/gecko/utils/logging"
"github.com/ava-labs/gecko/version"
cjson "github.com/ava-labs/gecko/utils/json"
)
// Info is the API service for unprivileged info on a node
type Info struct {
version version.Version
nodeID ids.ShortID
networkID uint32
log logging.Logger
networking network.Network
chainManager chains.Manager
}
// NewService returns a new admin API service
func NewService(log logging.Logger, version version.Version, nodeID ids.ShortID, networkID uint32, chainManager chains.Manager, peers network.Network) *common.HTTPHandler {
newServer := rpc.NewServer()
codec := cjson.NewCodec()
newServer.RegisterCodec(codec, "application/json")
newServer.RegisterCodec(codec, "application/json;charset=UTF-8")
newServer.RegisterService(&Info{
version: version,
nodeID: nodeID,
networkID: networkID,
log: log,
chainManager: chainManager,
networking: peers,
}, "info")
return &common.HTTPHandler{Handler: newServer}
}
// GetNodeVersionReply are the results from calling GetNodeVersion
type GetNodeVersionReply struct {
Version string `json:"version"`
}
// GetNodeVersion returns the version this node is running
func (service *Info) GetNodeVersion(_ *http.Request, _ *struct{}, reply *GetNodeVersionReply) error {
service.log.Info("Info: GetNodeVersion called")
reply.Version = service.version.String()
return nil
}
// GetNodeIDReply are the results from calling GetNodeID
type GetNodeIDReply struct {
NodeID ids.ShortID `json:"nodeID"`
}
// GetNodeID returns the node ID of this node
func (service *Info) GetNodeID(_ *http.Request, _ *struct{}, reply *GetNodeIDReply) error {
service.log.Info("Info: GetNodeID called")
reply.NodeID = service.nodeID
return nil
}
// GetNetworkIDReply are the results from calling GetNetworkID
type GetNetworkIDReply struct {
NetworkID cjson.Uint32 `json:"networkID"`
}
// GetNetworkID returns the network ID this node is running on
func (service *Info) GetNetworkID(_ *http.Request, _ *struct{}, reply *GetNetworkIDReply) error {
service.log.Info("Info: GetNetworkID called")
reply.NetworkID = cjson.Uint32(service.networkID)
return nil
}
// GetNetworkNameReply is the result from calling GetNetworkName
type GetNetworkNameReply struct {
NetworkName string `json:"networkName"`
}
// GetNetworkName returns the network name this node is running on
func (service *Info) GetNetworkName(_ *http.Request, _ *struct{}, reply *GetNetworkNameReply) error {
service.log.Info("Info: GetNetworkName called")
reply.NetworkName = genesis.NetworkName(service.networkID)
return nil
}
// GetBlockchainIDArgs are the arguments for calling GetBlockchainID
type GetBlockchainIDArgs struct {
Alias string `json:"alias"`
}
// GetBlockchainIDReply are the results from calling GetBlockchainID
type GetBlockchainIDReply struct {
BlockchainID string `json:"blockchainID"`
}
// GetBlockchainID returns the blockchain ID that resolves the alias that was supplied
func (service *Info) GetBlockchainID(_ *http.Request, args *GetBlockchainIDArgs, reply *GetBlockchainIDReply) error {
service.log.Info("Info: GetBlockchainID called")
bID, err := service.chainManager.Lookup(args.Alias)
reply.BlockchainID = bID.String()
return err
}
// PeersReply are the results from calling Peers
type PeersReply struct {
Peers []network.PeerID `json:"peers"`
}
// Peers returns the list of current validators
func (service *Info) Peers(_ *http.Request, _ *struct{}, reply *PeersReply) error {
service.log.Info("Info: Peers called")
reply.Peers = service.networking.Peers()
return nil
}

View File

@ -12,6 +12,8 @@ import (
"github.com/gorilla/rpc/v2"
zxcvbn "github.com/nbutton23/zxcvbn-go"
"github.com/ava-labs/gecko/chains/atomic"
"github.com/ava-labs/gecko/database"
"github.com/ava-labs/gecko/database/encdb"
@ -19,12 +21,11 @@ import (
"github.com/ava-labs/gecko/database/prefixdb"
"github.com/ava-labs/gecko/ids"
"github.com/ava-labs/gecko/snow/engine/common"
"github.com/ava-labs/gecko/utils/codec"
"github.com/ava-labs/gecko/utils/formatting"
"github.com/ava-labs/gecko/utils/logging"
"github.com/ava-labs/gecko/utils/codec"
jsoncodec "github.com/ava-labs/gecko/utils/json"
zxcvbn "github.com/nbutton23/zxcvbn-go"
)
const (

View File

@ -4,9 +4,10 @@
package metrics
import (
"github.com/ava-labs/gecko/snow/engine/common"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/ava-labs/gecko/snow/engine/common"
)
// NewService returns a new prometheus service

View File

@ -10,9 +10,9 @@ import (
"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/codec"
"github.com/ava-labs/gecko/utils/hashing"
"github.com/ava-labs/gecko/utils/logging"
"github.com/ava-labs/gecko/utils/codec"
)
type rcLock struct {

View File

@ -13,8 +13,8 @@ import (
"github.com/ava-labs/gecko/database"
"github.com/ava-labs/gecko/database/nodb"
"github.com/ava-labs/gecko/utils"
"github.com/ava-labs/gecko/utils/hashing"
"github.com/ava-labs/gecko/utils/codec"
"github.com/ava-labs/gecko/utils/hashing"
)
// Database encrypts all values that are provided

View File

@ -6,14 +6,15 @@ package leveldb
import (
"bytes"
"github.com/ava-labs/gecko/database"
"github.com/ava-labs/gecko/utils"
"github.com/syndtr/goleveldb/leveldb"
"github.com/syndtr/goleveldb/leveldb/errors"
"github.com/syndtr/goleveldb/leveldb/filter"
"github.com/syndtr/goleveldb/leveldb/iterator"
"github.com/syndtr/goleveldb/leveldb/opt"
"github.com/syndtr/goleveldb/leveldb/util"
"github.com/ava-labs/gecko/database"
"github.com/ava-labs/gecko/utils"
)
const (

View File

@ -17,7 +17,7 @@ func (*Database) Has([]byte) (bool, error) { return false, database.ErrClosed }
func (*Database) Get([]byte) ([]byte, error) { return nil, database.ErrClosed }
// Put returns nil
func (*Database) Put(_ []byte, _ []byte) error { return database.ErrClosed }
func (*Database) Put(_, _ []byte) error { return database.ErrClosed }
// Delete returns nil
func (*Database) Delete([]byte) error { return database.ErrClosed }

View File

@ -27,7 +27,7 @@ func NewClient(client rpcdbproto.DatabaseClient) *DatabaseClient {
return &DatabaseClient{client: client}
}
// Has returns false, nil
// Has attempts to return if the database has a key with the provided value.
func (db *DatabaseClient) Has(key []byte) (bool, error) {
resp, err := db.client.Has(context.Background(), &rpcdbproto.HasRequest{
Key: key,
@ -38,7 +38,7 @@ func (db *DatabaseClient) Has(key []byte) (bool, error) {
return resp.Has, nil
}
// Get returns nil, error
// Get attempts to return the value that was mapped to the key that was provided
func (db *DatabaseClient) Get(key []byte) ([]byte, error) {
resp, err := db.client.Get(context.Background(), &rpcdbproto.GetRequest{
Key: key,
@ -49,7 +49,7 @@ func (db *DatabaseClient) Get(key []byte) ([]byte, error) {
return resp.Value, nil
}
// Put returns nil
// Put attempts to set the value this key maps to
func (db *DatabaseClient) Put(key, value []byte) error {
_, err := db.client.Put(context.Background(), &rpcdbproto.PutRequest{
Key: key,
@ -58,7 +58,7 @@ func (db *DatabaseClient) Put(key, value []byte) error {
return updateError(err)
}
// Delete returns nil
// Delete attempts to remove any mapping from the key
func (db *DatabaseClient) Delete(key []byte) error {
_, err := db.client.Delete(context.Background(), &rpcdbproto.DeleteRequest{
Key: key,
@ -99,7 +99,7 @@ func (db *DatabaseClient) NewIteratorWithStartAndPrefix(start, prefix []byte) da
}
}
// Stat returns an error
// Stat attempts to return the statistic of this database
func (db *DatabaseClient) Stat(property string) (string, error) {
resp, err := db.client.Stat(context.Background(), &rpcdbproto.StatRequest{
Property: property,
@ -110,7 +110,7 @@ func (db *DatabaseClient) Stat(property string) (string, error) {
return resp.Stat, nil
}
// Compact returns nil
// Compact attempts to optimize the space utilization in the provided range
func (db *DatabaseClient) Compact(start, limit []byte) error {
_, err := db.client.Compact(context.Background(), &rpcdbproto.CompactRequest{
Start: start,
@ -119,7 +119,7 @@ func (db *DatabaseClient) Compact(start, limit []byte) error {
return updateError(err)
}
// Close returns nil
// Close attempts to close the database
func (db *DatabaseClient) Close() error {
_, err := db.client.Close(context.Background(), &rpcdbproto.CloseRequest{})
return updateError(err)
@ -207,7 +207,8 @@ type iterator struct {
err error
}
// Next returns false
// Next attempts to move the iterator to the next element and returns if this
// succeeded
func (it *iterator) Next() bool {
resp, err := it.db.client.IteratorNext(context.Background(), &rpcdbproto.IteratorNextRequest{
Id: it.id,
@ -221,7 +222,7 @@ func (it *iterator) Next() bool {
return resp.FoundNext
}
// Error returns any errors
// Error returns any that occurred while iterating
func (it *iterator) Error() error {
if it.err != nil {
return it.err
@ -234,19 +235,21 @@ func (it *iterator) Error() error {
return it.err
}
// Key returns nil
// Key returns the key of the current element
func (it *iterator) Key() []byte { return it.key }
// Value returns nil
// Value returns the value of the current element
func (it *iterator) Value() []byte { return it.value }
// Release does nothing
// Release frees any resources held by the iterator
func (it *iterator) Release() {
it.db.client.IteratorRelease(context.Background(), &rpcdbproto.IteratorReleaseRequest{
Id: it.id,
})
}
// updateError sets the error value to the errors required by the Database
// interface
func updateError(err error) error {
if err == nil {
return nil

View File

@ -34,16 +34,16 @@ func NewServer(db database.Database) *DatabaseServer {
}
}
// Has ...
// Has delegates the Has call to the managed database and returns the result
func (db *DatabaseServer) Has(_ context.Context, req *rpcdbproto.HasRequest) (*rpcdbproto.HasResponse, error) {
has, err := db.db.Has(req.Key)
if err != nil {
return nil, err
}
return &rpcdbproto.HasResponse{Has: has}, nil
return &rpcdbproto.HasResponse{Has: has}, err
}
// Get ...
// Get delegates the Get call to the managed database and returns the result
func (db *DatabaseServer) Get(_ context.Context, req *rpcdbproto.GetRequest) (*rpcdbproto.GetResponse, error) {
value, err := db.db.Get(req.Key)
if err != nil {
@ -52,17 +52,18 @@ func (db *DatabaseServer) Get(_ context.Context, req *rpcdbproto.GetRequest) (*r
return &rpcdbproto.GetResponse{Value: value}, nil
}
// Put ...
// Put delegates the Put call to the managed database and returns the result
func (db *DatabaseServer) Put(_ context.Context, req *rpcdbproto.PutRequest) (*rpcdbproto.PutResponse, error) {
return &rpcdbproto.PutResponse{}, db.db.Put(req.Key, req.Value)
}
// Delete ...
// Delete delegates the Delete call to the managed database and returns the
// result
func (db *DatabaseServer) Delete(_ context.Context, req *rpcdbproto.DeleteRequest) (*rpcdbproto.DeleteResponse, error) {
return &rpcdbproto.DeleteResponse{}, db.db.Delete(req.Key)
}
// Stat ...
// Stat delegates the Stat call to the managed database and returns the result
func (db *DatabaseServer) Stat(_ context.Context, req *rpcdbproto.StatRequest) (*rpcdbproto.StatResponse, error) {
stat, err := db.db.Stat(req.Property)
if err != nil {
@ -71,17 +72,19 @@ func (db *DatabaseServer) Stat(_ context.Context, req *rpcdbproto.StatRequest) (
return &rpcdbproto.StatResponse{Stat: stat}, nil
}
// Compact ...
// Compact delegates the Compact call to the managed database and returns the
// result
func (db *DatabaseServer) Compact(_ context.Context, req *rpcdbproto.CompactRequest) (*rpcdbproto.CompactResponse, error) {
return &rpcdbproto.CompactResponse{}, db.db.Compact(req.Start, req.Limit)
}
// Close ...
func (db *DatabaseServer) Close(_ context.Context, _ *rpcdbproto.CloseRequest) (*rpcdbproto.CloseResponse, error) {
// Close delegates the Close call to the managed database and returns the result
func (db *DatabaseServer) Close(context.Context, *rpcdbproto.CloseRequest) (*rpcdbproto.CloseResponse, error) {
return &rpcdbproto.CloseResponse{}, db.db.Close()
}
// WriteBatch ...
// WriteBatch takes in a set of key-value pairs and atomically writes them to
// the internal database
func (db *DatabaseServer) WriteBatch(_ context.Context, req *rpcdbproto.WriteBatchRequest) (*rpcdbproto.WriteBatchResponse, error) {
db.batch.Reset()
@ -100,7 +103,8 @@ func (db *DatabaseServer) WriteBatch(_ context.Context, req *rpcdbproto.WriteBat
return &rpcdbproto.WriteBatchResponse{}, db.batch.Write()
}
// NewIteratorWithStartAndPrefix ...
// NewIteratorWithStartAndPrefix allocates an iterator and returns the iterator
// ID
func (db *DatabaseServer) NewIteratorWithStartAndPrefix(_ context.Context, req *rpcdbproto.NewIteratorWithStartAndPrefixRequest) (*rpcdbproto.NewIteratorWithStartAndPrefixResponse, error) {
id := db.nextIteratorID
it := db.db.NewIteratorWithStartAndPrefix(req.Start, req.Prefix)
@ -110,7 +114,7 @@ func (db *DatabaseServer) NewIteratorWithStartAndPrefix(_ context.Context, req *
return &rpcdbproto.NewIteratorWithStartAndPrefixResponse{Id: id}, nil
}
// IteratorNext ...
// IteratorNext attempts to call next on the requested iterator
func (db *DatabaseServer) IteratorNext(_ context.Context, req *rpcdbproto.IteratorNextRequest) (*rpcdbproto.IteratorNextResponse, error) {
it, exists := db.iterators[req.Id]
if !exists {
@ -123,7 +127,7 @@ func (db *DatabaseServer) IteratorNext(_ context.Context, req *rpcdbproto.Iterat
}, nil
}
// IteratorError ...
// IteratorError attempts to report any errors that occurred during iteration
func (db *DatabaseServer) IteratorError(_ context.Context, req *rpcdbproto.IteratorErrorRequest) (*rpcdbproto.IteratorErrorResponse, error) {
it, exists := db.iterators[req.Id]
if !exists {
@ -132,7 +136,7 @@ func (db *DatabaseServer) IteratorError(_ context.Context, req *rpcdbproto.Itera
return &rpcdbproto.IteratorErrorResponse{}, it.Error()
}
// IteratorRelease ...
// IteratorRelease attempts to release the resources allocated to an iterator
func (db *DatabaseServer) IteratorRelease(_ context.Context, req *rpcdbproto.IteratorReleaseRequest) (*rpcdbproto.IteratorReleaseResponse, error) {
it, exists := db.iterators[req.Id]
if exists {

View File

@ -18,27 +18,27 @@ import (
// 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/" + EVMID.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"},
"vm/" + platformvm.ID.String(): {"vm/platform"},
"vm/" + avm.ID.String(): {"vm/avm"},
"vm/" + EVMID.String(): {"vm/evm"},
"vm/" + spdagvm.ID.String(): {"vm/spdag"},
"vm/" + spchainvm.ID.String(): {"vm/spchain"},
"vm/" + timestampvm.ID.String(): {"vm/timestamp"},
"bc/" + ids.Empty.String(): {"P", "platform", "bc/P", "bc/platform"},
}
chainAliases := map[[32]byte][]string{
ids.Empty.Key(): []string{"P", "platform"},
ids.Empty.Key(): {"P", "platform"},
}
vmAliases := map[[32]byte][]string{
platformvm.ID.Key(): []string{"platform"},
avm.ID.Key(): []string{"avm"},
EVMID.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"},
platformvm.ID.Key(): {"platform"},
avm.ID.Key(): {"avm"},
EVMID.Key(): {"evm"},
spdagvm.ID.Key(): {"spdag"},
spchainvm.ID.Key(): {"spchain"},
timestampvm.ID.Key(): {"timestamp"},
secp256k1fx.ID.Key(): {"secp256k1fx"},
nftfx.ID.Key(): {"nftfx"},
propertyfx.ID.Key(): {"propertyfx"},
}
genesisBytes, err := Genesis(networkID)

View File

@ -9,12 +9,12 @@ import (
"time"
"github.com/ava-labs/gecko/ids"
"github.com/ava-labs/gecko/utils/codec"
"github.com/ava-labs/gecko/utils/formatting"
"github.com/ava-labs/gecko/utils/json"
"github.com/ava-labs/gecko/utils/units"
"github.com/ava-labs/gecko/utils/wrappers"
"github.com/ava-labs/gecko/vms/avm"
"github.com/ava-labs/gecko/utils/codec"
"github.com/ava-labs/gecko/vms/nftfx"
"github.com/ava-labs/gecko/vms/platformvm"
"github.com/ava-labs/gecko/vms/propertyfx"
@ -156,7 +156,7 @@ func FromConfig(networkID uint32, config *Config) ([]byte, error) {
// 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,
@ -167,25 +167,25 @@ func FromConfig(networkID uint32, config *Config) ([]byte, error) {
},
Name: "X-Chain",
},
platformvm.APIChain{
{
GenesisData: formatting.CB58{Bytes: config.EVMBytes},
SubnetID: platformvm.DefaultSubnetID,
VMID: EVMID,
Name: "C-Chain",
},
platformvm.APIChain{
{
GenesisData: spdagvmReply.Bytes,
SubnetID: platformvm.DefaultSubnetID,
VMID: spdagvm.ID,
Name: "Simple DAG Payments",
},
platformvm.APIChain{
{
GenesisData: spchainvmReply.Bytes,
SubnetID: platformvm.DefaultSubnetID,
VMID: spchainvm.ID,
Name: "Simple Chain Payments",
},
platformvm.APIChain{
{
GenesisData: formatting.CB58{Bytes: []byte{}}, // There is no genesis data
SubnetID: platformvm.DefaultSubnetID,
VMID: timestampvm.ID,

7
go.sum
View File

@ -64,6 +64,7 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 h1:FtmdgXiUlNeRsoNMFlKLDt+S+6hbjVMEW6RGQ7aUf7c=
github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0=
github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw=
github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
github.com/frankban/quicktest v1.7.2/go.mod h1:jaStnuzAqU1AJdCO0l53JDCJrVDKcS03DbaAcR7Ks/o=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
@ -122,6 +123,7 @@ github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+l
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb h1:b5rjCoWHc7eqmAS4/qyk21ZsHyb6Mxv/jykxvNTkU4M=
github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/huin/goupnp v1.0.0 h1:wg75sLpL6DZqwHQN6E1Cfk6mtfzS45z8OV+ic+DtHRo=
github.com/huin/goupnp v1.0.0/go.mod h1:n9v9KO1tAxYH82qOn+UTIFQDmx5n1Zxd/ClZDMX7Bnc=
@ -177,8 +179,10 @@ github.com/olekukonko/tablewriter v0.0.4 h1:vHD/YYe1Wolo78koG299f7V/VAS08c6IpCLn
github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.10.1 h1:q/mM8GF/n0shIN8SaAZ0V+jnLPzen6WIVZdiwrRlMlo=
github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME=
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/openconfig/gnmi v0.0.0-20190823184014-89b2bf29312c/go.mod h1:t+O9It+LKzfOAhKTT5O0ehDix+MTqbtT0T9t+7zzOvc=
github.com/openconfig/reference v0.0.0-20190727015836-8dfd928c9696/go.mod h1:ym2A+zigScwkSEb/cVQB0/ZMpU3rqiH6X7WRRsxgOGw=
@ -230,6 +234,7 @@ github.com/steakknife/bloomfilter v0.0.0-20180922174646-6819c0d2a570/go.mod h1:8
github.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3 h1:njlZPzLwU639dk2kqnCPPv+wNjq7Xb6EfUxe/oX0/NM=
github.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3/go.mod h1:hpGUWaI9xL8pRQCTXQgocU38Qw1g0Us7n5PxxTwTCYU=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
@ -345,6 +350,7 @@ gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLks
gopkg.in/bsm/ratelimit.v1 v1.0.0-20160220154919-db14e161995a/go.mod h1:KF9sEfUPAXdG8Oev9e99iLGnl2uJMjc5B+4y3O7x610=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/jcmturner/aescts.v1 v1.0.1/go.mod h1:nsR8qBOg+OucoIW+WMhB3GspUQXq9XorLnQb9XtvcOo=
gopkg.in/jcmturner/dnsutils.v1 v1.0.1/go.mod h1:m3v+5svpVOhtFAP/wSz+yzh4Mc0Fg7eRhxkJMWSIz9Q=
@ -354,6 +360,7 @@ gopkg.in/jcmturner/rpc.v1 v1.1.0/go.mod h1:YIdkC4XfD6GXbzje11McwsDuOlZQSb9W4vfLv
gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200316214253-d7b0ff38cac9 h1:ITeyKbRetrVzqR3U1eY+ywgp7IBspGd1U/bkwd1gWu4=
gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200316214253-d7b0ff38cac9/go.mod h1:uAJfkITjFhyEEuUfm7bsmCZRbW5WRq8s9EY8HZ6hCns=
gopkg.in/redis.v4 v4.2.4/go.mod h1:8KREHdypkCEojGKQcjMqAODMICIVwZAONWq8RowTITA=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/urfave/cli.v1 v1.20.0 h1:NdAVW6RYxDif9DhDHaAortIu956m2c0v+09AZBPTbE0=
gopkg.in/urfave/cli.v1 v1.20.0/go.mod h1:vuBzUtMdQeixQj8LVd+/98pzhxNGQoyuPBlsXHOQNO0=

View File

@ -226,6 +226,7 @@ func init() {
// Enable/Disable APIs:
fs.BoolVar(&Config.AdminAPIEnabled, "api-admin-enabled", true, "If true, this node exposes the Admin API")
fs.BoolVar(&Config.InfoAPIEnabled, "api-info-enabled", true, "If true, this node exposes the Info API")
fs.BoolVar(&Config.KeystoreAPIEnabled, "api-keystore-enabled", true, "If true, this node exposes the Keystore API")
fs.BoolVar(&Config.MetricsAPIEnabled, "api-metrics-enabled", true, "If true, this node exposes the Metrics API")
fs.BoolVar(&Config.HealthAPIEnabled, "api-health-enabled", true, "If true, this node exposes the Health API")

View File

@ -51,6 +51,7 @@ type Config struct {
// Enable/Disable APIs
AdminAPIEnabled bool
InfoAPIEnabled bool
KeystoreAPIEnabled bool
MetricsAPIEnabled bool
HealthAPIEnabled bool

View File

@ -18,6 +18,7 @@ import (
"github.com/ava-labs/gecko/api"
"github.com/ava-labs/gecko/api/admin"
"github.com/ava-labs/gecko/api/health"
"github.com/ava-labs/gecko/api/info"
"github.com/ava-labs/gecko/api/ipcs"
"github.com/ava-labs/gecko/api/keystore"
"github.com/ava-labs/gecko/api/metrics"
@ -461,11 +462,19 @@ func (n *Node) initMetricsAPI() {
func (n *Node) initAdminAPI() {
if n.Config.AdminAPIEnabled {
n.Log.Info("initializing Admin API")
service := admin.NewService(Version, n.ID, n.Config.NetworkID, n.Log, n.chainManager, n.Net, &n.APIServer)
service := admin.NewService(n.Log, n.chainManager, n.Net, &n.APIServer)
n.APIServer.AddRoute(service, &sync.RWMutex{}, "admin", "", n.HTTPLog)
}
}
func (n *Node) initInfoAPI() {
if n.Config.InfoAPIEnabled {
n.Log.Info("initializing Info API")
service := info.NewService(n.Log, Version, n.ID, n.Config.NetworkID, n.chainManager, n.Net)
n.APIServer.AddRoute(service, &sync.RWMutex{}, "info", "", n.HTTPLog)
}
}
// initHealthAPI initializes the Health API service
// Assumes n.Log, n.ConsensusAPI, and n.ValidatorAPI already initialized
func (n *Node) initHealthAPI() {
@ -562,6 +571,7 @@ func (n *Node) Initialize(Config *Config, logger logging.Logger, logFactory logg
n.initChainManager() // Set up the chain manager
n.initAdminAPI() // Start the Admin API
n.initInfoAPI() // Start the Info API
n.initHealthAPI() // Start the Health API
n.initIPCAPI() // Start the IPC API

View File

@ -125,14 +125,14 @@ func TestParametersAnotherInvalidBetaRogue(t *testing.T) {
func TestParametersInvalidConcurrentRepolls(t *testing.T) {
tests := []Parameters{
Parameters{
{
K: 1,
Alpha: 1,
BetaVirtuous: 1,
BetaRogue: 1,
ConcurrentRepolls: 2,
},
Parameters{
{
K: 1,
Alpha: 1,
BetaVirtuous: 1,

View File

@ -107,6 +107,9 @@ func (b *bootstrapper) fetch(vtxID ids.ID) error {
// Make sure we don't already have this vertex
if _, err := b.State.GetVertex(vtxID); err == nil {
if numPending := b.outstandingRequests.Len(); numPending == 0 && b.processedStartingAcceptedFrontier {
return b.finish()
}
return nil
}
@ -124,15 +127,12 @@ func (b *bootstrapper) fetch(vtxID ids.ID) error {
// Process vertices
func (b *bootstrapper) process(vtx avalanche.Vertex) error {
toProcess := []avalanche.Vertex{vtx}
for len(toProcess) > 0 {
newLen := len(toProcess) - 1
vtx := toProcess[newLen]
toProcess = toProcess[:newLen]
if _, ok := b.processedCache.Get(vtx.ID()); ok { // already processed this
continue
}
toProcess := newMaxVertexHeap()
if _, ok := b.processedCache.Get(vtx.ID()); !ok { // only process if we haven't already
toProcess.Push(vtx)
}
for toProcess.Len() > 0 {
vtx := toProcess.Pop()
switch vtx.Status() {
case choices.Unknown:
if err := b.fetch(vtx.ID()); err != nil {
@ -168,7 +168,9 @@ func (b *bootstrapper) process(vtx avalanche.Vertex) error {
}
}
for _, parent := range vtx.Parents() {
toProcess = append(toProcess, parent)
if _, ok := b.processedCache.Get(parent.ID()); !ok { // already processed this
toProcess.Push(parent)
}
}
b.processedCache.Put(vtx.ID(), nil)
}

View File

@ -805,3 +805,113 @@ func TestBootstrapperIncompleteMultiPut(t *testing.T) {
t.Fatal("should be accepted")
}
}
func TestBootstrapperFinalized(t *testing.T) {
config, peerID, sender, state, vm := newConfig(t)
vtxID0 := ids.Empty.Prefix(0)
vtxID1 := ids.Empty.Prefix(1)
vtxBytes0 := []byte{0}
vtxBytes1 := []byte{1}
vtx0 := &Vtx{
id: vtxID0,
height: 0,
status: choices.Unknown,
bytes: vtxBytes0,
}
vtx1 := &Vtx{
id: vtxID1,
height: 1,
parents: []avalanche.Vertex{vtx0},
status: choices.Unknown,
bytes: vtxBytes1,
}
bs := bootstrapper{}
bs.metrics.Initialize(config.Context.Log, fmt.Sprintf("gecko_%s", config.Context.ChainID), prometheus.NewRegistry())
bs.Initialize(config)
finished := new(bool)
bs.onFinished = func() error { *finished = true; return nil }
acceptedIDs := ids.Set{}
acceptedIDs.Add(vtxID0)
acceptedIDs.Add(vtxID1)
parsedVtx0 := false
parsedVtx1 := false
state.getVertex = func(vtxID ids.ID) (avalanche.Vertex, error) {
switch {
case vtxID.Equals(vtxID0):
if parsedVtx0 {
return vtx0, nil
}
return nil, errUnknownVertex
case vtxID.Equals(vtxID1):
if parsedVtx1 {
return vtx1, nil
}
return nil, errUnknownVertex
default:
t.Fatal(errUnknownVertex)
panic(errUnknownVertex)
}
}
state.parseVertex = func(vtxBytes []byte) (avalanche.Vertex, error) {
switch {
case bytes.Equal(vtxBytes, vtxBytes0):
vtx0.status = choices.Processing
parsedVtx0 = true
return vtx0, nil
case bytes.Equal(vtxBytes, vtxBytes1):
vtx1.status = choices.Processing
parsedVtx1 = true
return vtx1, nil
}
t.Fatal(errUnknownVertex)
return nil, errUnknownVertex
}
requestIDs := map[[32]byte]uint32{}
sender.GetAncestorsF = func(vdr ids.ShortID, reqID uint32, vtxID ids.ID) {
if !vdr.Equals(peerID) {
t.Fatalf("Should have requested block from %s, requested from %s", peerID, vdr)
}
requestIDs[vtxID.Key()] = reqID
}
vm.CantBootstrapping = false
if err := bs.ForceAccepted(acceptedIDs); err != nil { // should request vtx0 and vtx1
t.Fatal(err)
}
reqID, ok := requestIDs[vtxID1.Key()]
if !ok {
t.Fatalf("should have requested vtx1")
}
vm.CantBootstrapped = false
if err := bs.MultiPut(peerID, reqID, [][]byte{vtxBytes1, vtxBytes0}); err != nil {
t.Fatal(err)
}
reqID, ok = requestIDs[vtxID0.Key()]
if !ok {
t.Fatalf("should have requested vtx0")
}
if err := bs.GetAncestorsFailed(peerID, reqID); err != nil {
t.Fatal(err)
}
if !*finished {
t.Fatalf("Bootstrapping should have finished")
} else if vtx0.Status() != choices.Accepted {
t.Fatalf("Vertex should be accepted")
} else if vtx1.Status() != choices.Accepted {
t.Fatalf("Vertex should be accepted")
}
}

View File

@ -115,6 +115,9 @@ func (b *bootstrapper) fetch(blkID ids.ID) error {
// Make sure we don't already have this block
if _, err := b.VM.GetBlock(blkID); err == nil {
if numPending := b.outstandingRequests.Len(); numPending == 0 && b.processedStartingAcceptedFrontier {
return b.finish()
}
return nil
}

View File

@ -622,3 +622,128 @@ func TestBootstrapperFilterAccepted(t *testing.T) {
t.Fatalf("Blk shouldn't be accepted")
}
}
func TestBootstrapperFinalized(t *testing.T) {
config, peerID, sender, vm := newConfig(t)
blkID0 := ids.Empty.Prefix(0)
blkID1 := ids.Empty.Prefix(1)
blkID2 := ids.Empty.Prefix(2)
blkBytes0 := []byte{0}
blkBytes1 := []byte{1}
blkBytes2 := []byte{2}
blk0 := &Blk{
id: blkID0,
height: 0,
status: choices.Accepted,
bytes: blkBytes0,
}
blk1 := &Blk{
parent: blk0,
id: blkID1,
height: 1,
status: choices.Unknown,
bytes: blkBytes1,
}
blk2 := &Blk{
parent: blk1,
id: blkID2,
height: 2,
status: choices.Unknown,
bytes: blkBytes2,
}
bs := bootstrapper{}
bs.metrics.Initialize(config.Context.Log, fmt.Sprintf("gecko_%s", config.Context.ChainID), prometheus.NewRegistry())
bs.Initialize(config)
finished := new(bool)
bs.onFinished = func() error { *finished = true; return nil }
acceptedIDs := ids.Set{}
acceptedIDs.Add(blkID1)
acceptedIDs.Add(blkID2)
parsedBlk1 := false
parsedBlk2 := false
vm.GetBlockF = func(blkID ids.ID) (snowman.Block, error) {
switch {
case blkID.Equals(blkID0):
return blk0, nil
case blkID.Equals(blkID1):
if parsedBlk1 {
return blk1, nil
}
return nil, errUnknownBlock
case blkID.Equals(blkID2):
if parsedBlk2 {
return blk2, nil
}
return nil, errUnknownBlock
default:
t.Fatal(errUnknownBlock)
panic(errUnknownBlock)
}
}
vm.ParseBlockF = func(blkBytes []byte) (snowman.Block, error) {
switch {
case bytes.Equal(blkBytes, blkBytes0):
return blk0, nil
case bytes.Equal(blkBytes, blkBytes1):
blk1.status = choices.Processing
parsedBlk1 = true
return blk1, nil
case bytes.Equal(blkBytes, blkBytes2):
blk2.status = choices.Processing
parsedBlk2 = true
return blk2, nil
}
t.Fatal(errUnknownBlock)
return nil, errUnknownBlock
}
requestIDs := map[[32]byte]uint32{}
sender.GetAncestorsF = func(vdr ids.ShortID, reqID uint32, vtxID ids.ID) {
if !vdr.Equals(peerID) {
t.Fatalf("Should have requested block from %s, requested from %s", peerID, vdr)
}
requestIDs[vtxID.Key()] = reqID
}
vm.CantBootstrapping = false
if err := bs.ForceAccepted(acceptedIDs); err != nil { // should request blk0 and blk1
t.Fatal(err)
}
reqID, ok := requestIDs[blkID2.Key()]
if !ok {
t.Fatalf("should have requested blk2")
}
vm.CantBootstrapped = false
if err := bs.MultiPut(peerID, reqID, [][]byte{blkBytes2, blkBytes1}); err != nil {
t.Fatal(err)
}
reqID, ok = requestIDs[blkID1.Key()]
if !ok {
t.Fatalf("should have requested blk1")
}
if err := bs.GetAncestorsFailed(peerID, reqID); err != nil {
t.Fatal(err)
}
if !*finished {
t.Fatalf("Bootstrapping should have finished")
} else if blk0.Status() != choices.Accepted {
t.Fatalf("Block should be accepted")
} else if blk1.Status() != choices.Accepted {
t.Fatalf("Block should be accepted")
} else if blk2.Status() != choices.Accepted {
t.Fatalf("Block should be accepted")
}
}

View File

@ -34,8 +34,7 @@ type Block struct {
func (b *Block) Initialize(bytes []byte, vm *SnowmanVM) {
b.VM = vm
b.Metadata.Initialize(bytes)
status := b.VM.State.GetStatus(vm.DB, b.ID())
b.SetStatus(status)
b.SetStatus(choices.Unknown) // don't set status until it is queried
}
// ParentID returns [b]'s parent's ID
@ -55,7 +54,6 @@ func (b *Block) Parent() snowman.Block {
// Recall that b.vm.DB.Commit() must be called to persist to the DB
func (b *Block) Accept() error {
b.SetStatus(choices.Accepted) // Change state of this block
blkID := b.ID()
// Persist data

View File

@ -0,0 +1,48 @@
package core
import (
"testing"
"github.com/ava-labs/gecko/snow/choices"
"github.com/ava-labs/gecko/snow/consensus/snowman"
"github.com/ava-labs/gecko/ids"
"github.com/ava-labs/gecko/database/memdb"
"github.com/ava-labs/gecko/database/versiondb"
)
func TestBlock(t *testing.T) {
parentID := ids.NewID([32]byte{1, 2, 3, 4, 5})
db := versiondb.New(memdb.New())
state, err := NewSnowmanState(func([]byte) (snowman.Block, error) { return nil, nil })
if err != nil {
t.Fatal(err)
}
b := NewBlock(parentID)
b.Initialize([]byte{1, 2, 3}, &SnowmanVM{
DB: db,
State: state,
})
// should be unknown until someone queries for it
if status := b.Metadata.status; status != choices.Unknown {
t.Fatalf("status should be unknown but is %s", status)
}
// querying should change status to processing
if status := b.Status(); status != choices.Processing {
t.Fatalf("status should be processing but is %s", status)
}
b.Accept()
if status := b.Status(); status != choices.Accepted {
t.Fatalf("status should be accepted but is %s", status)
}
b.Reject()
if status := b.Status(); status != choices.Rejected {
t.Fatalf("status should be rejected but is %s", status)
}
}

View File

@ -128,19 +128,10 @@ func (s *state) Get(db database.Database, typeID uint64, key ids.ID) (interface{
// The unique ID of this key/typeID pair
uID := s.uniqueID(key, typeID)
// See if exists in database
exists, err := db.Has(uID.Bytes())
if err != nil {
return nil, err
}
if !exists {
return nil, database.ErrNotFound
}
// Get the value from the database
valueBytes, err := db.Get(uID.Bytes())
if err != nil {
return nil, fmt.Errorf("problem getting value from database: %w", err)
return nil, err
}
// Unmarshal the value from bytes and return it

View File

@ -128,7 +128,7 @@ func (tx *addDefaultSubnetDelegatorTx) SemanticVerify(db database.Database) (*ve
// The account if this block's proposal is committed and the validator is
// added to the pending validator set. (Increase the account's nonce;
// decrease its balance.)
newAccount, err := account.Remove(0, tx.Nonce) // Remove also removes the fee
newAccount, err := account.Remove(tx.Wght, tx.Nonce) // Remove also removes the fee
if err != nil {
return nil, nil, nil, nil, permError{err}
}

View File

@ -386,4 +386,52 @@ func TestAddDefaultSubnetDelegatorTxSemanticVerify(t *testing.T) {
t.Fatal("should have failed verification because payer account has no $AVA to pay fee")
}
txFee = txFeeSaved // Reset tx fee
// Case 8: fail verification for spending more funds than it has
tx, err = vm.newAddDefaultSubnetDelegatorTx(
defaultNonce+1,
defaultBalance*2, // weight
uint64(defaultValidateStartTime.Unix()), // start time
uint64(defaultValidateEndTime.Unix()), // end time
defaultKey.PublicKey().Address(), // node ID
defaultKey.PublicKey().Address(), // destination
testNetworkID, // network ID
defaultKey, // tx fee payer
)
if err != nil {
t.Fatal(err)
}
_, _, _, _, err = tx.SemanticVerify(vm.DB)
if err == nil {
t.Fatal("should have failed verification because payer account spent twice the account's balance")
}
// Case 9: Confirm balance is correct
tx, err = vm.newAddDefaultSubnetDelegatorTx(
defaultNonce+1,
defaultStakeAmount, // weight
uint64(defaultValidateStartTime.Unix()), // start time
uint64(defaultValidateEndTime.Unix()), // end time
defaultKey.PublicKey().Address(), // node ID
defaultKey.PublicKey().Address(), // destination
testNetworkID, // network ID
defaultKey, // tx fee payer
)
if err != nil {
t.Fatal(err)
}
onCommitDB, _, _, _, err := tx.SemanticVerify(vm.DB)
if err != nil {
t.Fatal(err)
}
account, err := tx.vm.getAccount(onCommitDB, defaultKey.PublicKey().Address())
if err != nil {
t.Fatal(err)
}
balance := account.Balance
if balance != defaultBalance-(defaultStakeAmount+txFee) {
t.Fatalf("balance was not updated correctly after subnet delegator tx")
}
}