Skip to content

Commit

Permalink
Update validators and lts network (#1156)
Browse files Browse the repository at this point in the history
automatic validator power management, dynamic validators and LTS network

This commit introduces a new way to handle validators within the Vochain. 

Until now there was no way to create a new validator once the Genesis have been mined.
Now it is possible through a new transaction to update an account (publicKey) to Validator.
This transaction is expensive to avoid spamming the network with new validators.

In addition to that, the Vochain now tracks the validator metrics (score) based on their participation
on the block production process. Its power goes automatically from 0 to the maximum (currently 100).

If a validator stops working, the power will go to 0 and it will be removed from the validator set.

Finally, replace the existin `apex` network by the new `lts` network. The upcoming production blockchain.
--
Signed-off-by: p4u <[email protected]>
  • Loading branch information
p4u authored Oct 19, 2023
1 parent 51f4528 commit 34e4b58
Show file tree
Hide file tree
Showing 21 changed files with 537 additions and 117 deletions.
14 changes: 10 additions & 4 deletions api/api_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -254,11 +254,17 @@ type File struct {
type ValidatorList struct {
Validators []Validator `json:"validators"`
}

type Validator struct {
Power uint64 `json:"power"`
PubKey types.HexBytes `json:"pubKey" `
Address types.HexBytes `json:"address" `
Name string `json:"name"`
Power uint64 `json:"power"`
PubKey types.HexBytes `json:"pubKey"`
AccountAddress types.HexBytes `json:"address"`
Name string `json:"name"`
ValidatorAddress types.HexBytes `json:"validatorAddress"`
JoinHeight uint64 `json:"joinHeight"`
Votes uint64 `json:"votes"`
Proposals uint64 `json:"proposals"`
Score uint32 `json:"score"`
}

// Protobuf wrappers
Expand Down
13 changes: 9 additions & 4 deletions api/chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -708,10 +708,15 @@ func (a *API) chainValidatorsHandler(_ *apirest.APIdata, ctx *httprouter.HTTPCon
validators := ValidatorList{}
for _, v := range stateValidators {
validators.Validators = append(validators.Validators, Validator{
Address: v.GetAddress(),
Power: v.GetPower(),
Name: v.GetName(),
PubKey: v.GetPubKey(),
AccountAddress: v.GetAddress(),
ValidatorAddress: v.GetValidatorAddress(),
Power: v.GetPower(),
Name: v.GetName(),
PubKey: v.GetPubKey(),
JoinHeight: v.GetHeight(),
Votes: v.GetVotes(),
Proposals: v.GetProposals(),
Score: v.GetScore(),
})
}
data, err := json.Marshal(&validators)
Expand Down
58 changes: 56 additions & 2 deletions apiclient/account.go
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,58 @@ func (c *HTTPclient) AccountBootstrap(faucetPkg *models.FaucetPackage, metadata
return acc.TxHash, nil
}

// AccountSetValidator upgrades to validator status the account associated with the public key provided.
// If the public key is nil, the public key associated with the account client is used.
// Returns the transaction hash.
func (c *HTTPclient) AccountSetValidator(pubKey []byte, name string) (types.HexBytes, error) {
acc, err := c.Account("")
if err != nil {
return nil, fmt.Errorf("account not configured: %w", err)
}
if pubKey == nil {
pubKey = c.account.PublicKey()
}
// Build the transaction
stx := models.SignedTx{}
stx.Tx, err = proto.Marshal(&models.Tx{
Payload: &models.Tx_SetAccount{
SetAccount: &models.SetAccountTx{
Txtype: models.TxType_SET_ACCOUNT_VALIDATOR,
Nonce: &acc.Nonce,
PublicKey: pubKey,
Name: &name,
},
},
},
)
if err != nil {
return nil, fmt.Errorf("could not marshal transaction: %w", err)
}
stx.Signature, err = c.account.SignVocdoniTx(stx.Tx, c.ChainID())
if err != nil {
return nil, err
}
stxb, err := proto.Marshal(&stx)
if err != nil {
return nil, err
}
resp, code, err := c.Request(HTTPPOST, &api.Transaction{
Payload: stxb,
}, "chain", "transactions")
if err != nil {
return nil, err
}
if code != apirest.HTTPstatusOK {
return nil, fmt.Errorf("%s: %d (%s)", errCodeNot200, code, resp)
}
accv := &api.Transaction{}
err = json.Unmarshal(resp, accv)
if err != nil {
return nil, err
}
return accv.Hash, nil
}

// AccountSetMetadata updates the metadata associated with the account associated with the client.
func (c *HTTPclient) AccountSetMetadata(metadata *api.AccountMetadata) (types.HexBytes, error) {
var err error
Expand Down Expand Up @@ -258,7 +310,9 @@ func (c *HTTPclient) SetSIK(secret []byte) (types.HexBytes, error) {
Txtype: models.TxType_SET_ACCOUNT_SIK,
SIK: sik,
},
}})
},
},
)
if err != nil {
return nil, err
}
Expand All @@ -273,7 +327,7 @@ func (c *HTTPclient) SetSIK(secret []byte) (types.HexBytes, error) {
}
resp, code, err := c.Request(HTTPPOST, &api.Transaction{
Payload: stxb,
}, "chain", "transaction")
}, "chain", "transactions")
if err != nil {
return nil, err
}
Expand Down
114 changes: 106 additions & 8 deletions cmd/cli/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package main

import (
"encoding/base64"
"encoding/hex"
"encoding/json"
"fmt"
"net/http"
Expand All @@ -16,10 +17,12 @@ import (
flag "github.com/spf13/pflag"
"go.vocdoni.io/dvote/api"
"go.vocdoni.io/dvote/apiclient"
"go.vocdoni.io/dvote/crypto/ethereum"
"go.vocdoni.io/dvote/internal"
"go.vocdoni.io/dvote/log"
"go.vocdoni.io/dvote/types"
"go.vocdoni.io/dvote/util"
"go.vocdoni.io/dvote/vochain"
"go.vocdoni.io/proto/build/go/models"
)

Expand Down Expand Up @@ -80,10 +83,11 @@ func main() {
items.Sprint("🕸️\tNetwork info"), // 5
items.Sprint("📝\tBuild a new census"), // 6
items.Sprint("🗳️\tCreate an election"), // 7
items.Sprint("☑️\tVote"), // 8
items.Sprint("🖧\tChange API endpoint host"), // 9
items.Sprint("💾\tSave config to file"), // 10
items.Sprint("❌\tQuit"), // 11
items.Sprint("☑️\tSet validator"), // 8
items.Sprint("📝 Generate faucet package"), // 9
items.Sprint("🖧\tChange API endpoint host"), // 10
items.Sprint("💾\tSave config to file"), // 11
items.Sprint("❌\tQuit"), // 12
},
}

Expand Down Expand Up @@ -141,15 +145,23 @@ func main() {
if err := electionHandler(cli); err != nil {
errorp.Println(err)
}
case 8:
if err := accountSetValidator(cli); err != nil {
errorp.Println(err)
}
case 9:
if err := hostHandler(cli); err != nil {
if err := faucetPkg(cli); err != nil {
errorp.Println(err)
}
case 10:
if err := cli.save(); err != nil {
if err := hostHandler(cli); err != nil {
errorp.Println(err)
}
case 11:
if err := cli.save(); err != nil {
errorp.Println(err)
}
case 12:
os.Exit(0)
default:
errorp.Println("unknown option or not yet implemented")
Expand Down Expand Up @@ -342,7 +354,6 @@ func transfer(cli *VocdoniCLI) error {
}
dstAddress = account.Address
} else {

p := ui.Prompt{
Label: "destination address",
}
Expand Down Expand Up @@ -397,6 +408,52 @@ func transfer(cli *VocdoniCLI) error {
return nil
}

func faucetPkg(cli *VocdoniCLI) error {
// FaucetPackage represents the data of a faucet package
type FaucetPackage struct {
// FaucetPackagePayload is the Vocdoni faucet package payload
FaucetPayload []byte `json:"faucetPayload"`
// Signature is the signature for the vocdoni faucet payload
Signature []byte `json:"signature"`
}
signer := ethereum.SignKeys{}
if err := signer.AddHexKey(cli.getCurrentAccount().PrivKey.String()); err != nil {
return err
}
a := ui.Prompt{
Label: "destination address",
}
addrString, err := a.Run()
if err != nil {
return err
}
to := common.HexToAddress(addrString)
n := ui.Prompt{
Label: "amount",
}
amountString, err := n.Run()
if err != nil {
return err
}
amount, err := strconv.Atoi(amountString)
if err != nil {
return err
}
fpackage, err := vochain.GenerateFaucetPackage(&signer, to, uint64(amount))
if err != nil {
return err
}
fpackageBytes, err := json.Marshal(FaucetPackage{
FaucetPayload: fpackage.Payload,
Signature: fpackage.Signature,
})
if err != nil {
return err
}
infoPrint.Printf("faucet package for %s with amount %d: [ %s ]\n", to.Hex(), amount, base64.StdEncoding.EncodeToString(fpackageBytes))
return nil
}

func hostHandler(cli *VocdoniCLI) error {
validateFunc := func(url string) error {
log.Debugf("performing ping test to %s", url)
Expand Down Expand Up @@ -431,6 +488,48 @@ func hostHandler(cli *VocdoniCLI) error {
return cli.setAuthToken(token)
}

func accountSetValidator(cli *VocdoniCLI) error {
infoPrint.Printf("enter the name and a public key of the validator, leave it bank for using the selected account\n")

n := ui.Prompt{
Label: "name",
}
name, err := n.Run()
if err != nil {
return err
}

p := ui.Prompt{
Label: "public key",
}
pubKeyStr, err := p.Run()
if err != nil {
return err
}
pubKey := cli.getCurrentAccount().PublicKey
if pubKeyStr != "" {
pubKey, err = hex.DecodeString(pubKeyStr)
if err != nil {
return err
}
}

hash, err := cli.api.AccountSetValidator(pubKey, name)
if err != nil {
return err
}

infoPrint.Printf("transaction sent! hash %s\n", hash.String())
infoPrint.Printf("waiting for confirmation...")
ok := cli.waitForTransaction(hash)
if !ok {
return fmt.Errorf("transaction was not included")
}
infoPrint.Printf(" transaction confirmed!\n")

return nil
}

func accountSetMetadata(cli *VocdoniCLI) error {
currentAccount, err := cli.api.Account("")
if err != nil {
Expand Down Expand Up @@ -512,7 +611,6 @@ func accountSetMetadata(cli *VocdoniCLI) error {
return fmt.Errorf("transaction was not included")
}
return nil

}

func electionHandler(cli *VocdoniCLI) error {
Expand Down
14 changes: 13 additions & 1 deletion crypto/zk/circuit/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,19 @@ func (conf *ZkCircuitConfig) SupportsCensusSize(maxCensusSize uint64) bool {
var CircuitsConfigurations = map[string]*ZkCircuitConfig{
"dev": {
URI: "https://raw.githubusercontent.com/vocdoni/" +
"zk-franchise-proof-circuit/feature/new-circuit",
"zk-franchise-proof-circuit/master",
CircuitPath: "artifacts/zkCensus/dev/160",
Levels: 160, // ZkCircuit number of levels
ProvingKeyHash: hexToBytes("0xe359b256e5e3c78acaccf8dab5dc4bea99a2f07b2a05e935b5ca658c714dea4a"),
ProvingKeyFilename: "proving_key.zkey",
VerificationKeyHash: hexToBytes("0x235e55571812f8e324e73e37e53829db0c4ac8f68469b9b953876127c97b425f"),
VerificationKeyFilename: "verification_key.json",
WasmHash: hexToBytes("0x80a73567f6a4655d4332301efcff4bc5711bb48176d1c71fdb1e48df222ac139"),
WasmFilename: "circuit.wasm",
},
"prod": {
URI: "https://raw.githubusercontent.com/vocdoni/" +
"zk-franchise-proof-circuit/master",
CircuitPath: "artifacts/zkCensus/dev/160",
Levels: 160, // ZkCircuit number of levels
ProvingKeyHash: hexToBytes("0xe359b256e5e3c78acaccf8dab5dc4bea99a2f07b2a05e935b5ca658c714dea4a"),
Expand Down
1 change: 1 addition & 0 deletions dockerfiles/testsuite/env.gateway0
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
VOCDONI_DATADIR=/app/run
VOCDONI_LOGLEVEL=debug
VOCDONI_VOCHAIN_LOGLEVEL=error
VOCDONI_DEV=True
VOCDONI_ENABLEAPI=True
VOCDONI_ENABLERPC=True
Expand Down
2 changes: 1 addition & 1 deletion dockerfiles/testsuite/env.miner0
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ VOCDONI_MODE=miner
VOCDONI_LOGLEVEL=info
VOCDONI_DEV=True
VOCDONI_VOCHAIN_PUBLICADDR=miner0:26656
VOCDONI_VOCHAIN_LOGLEVEL=error
VOCDONI_VOCHAIN_LOGLEVEL=info
VOCDONI_VOCHAIN_SEEDS=3c3765494e758ae7baccb1f5b0661755302ddc47@seed:26656
VOCDONI_VOCHAIN_GENESIS=/app/misc/genesis.json
VOCDONI_VOCHAIN_MINERKEY=cda909c34901c137e12bb7d0afbcb9d1c8abc66f03862a42344b1f509d1ae4ce
Expand Down
11 changes: 6 additions & 5 deletions dockerfiles/testsuite/genesis.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,28 +31,28 @@
"consensus_pub_key": "038faa051e8a726597549bb057f1d296947bb54378443ec8fce030001ece678e14",
"power": 10,
"key_index": 1,
"name": ""
"name": "validator1"
},
{
"signer_address": "032faef5d0f2c76bbd804215e822a5203e83385d",
"consensus_pub_key": "03cf8d0d1afa561e01145a275d1e41ed1a6d652361509a4c93dfc6488fdf5eca38",
"power": 10,
"key_index": 2,
"name": ""
"name": "validator2"
},
{
"signer_address": "1f00b2ee957af530d44c8ceb1fecdd07c5702ad7",
"consensus_pub_key": "031802916d945239a39a9a8ee3e2eb3fb91ee324ccdfd73659f482e644892b796f",
"power": 10,
"key_index": 3,
"name": ""
"name": "validator3"
},
{
"signer_address": "8992487e178fdcdc0dad95174e2a6d6229b3719c",
"consensus_pub_key": "02a790726e98978b0ca2cde3a09cbb1af1b298191f46e051b86bcb1854deb58478",
"power": 10,
"key_index": 4,
"name": ""
"name": "validator4"
}
],
"accounts":[
Expand All @@ -74,7 +74,8 @@
"Tx_SetAccountInfoURI": 2,
"Tx_AddDelegateForAccount": 2,
"Tx_DelDelegateForAccount": 2,
"Tx_CollectFaucet": 1
"Tx_CollectFaucet": 1,
"Tx_SetAccountValidator": 100
}
}
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ require (
github.com/vocdoni/storage-proofs-eth-go v0.1.6
go.mongodb.org/mongo-driver v1.12.1
go.uber.org/atomic v1.11.0
go.vocdoni.io/proto v1.14.6-0.20230802094125-e07a41fda290
go.vocdoni.io/proto v1.15.4-0.20231017174559-1d9ea54cd9ad
golang.org/x/crypto v0.14.0
golang.org/x/exp v0.0.0-20230905200255-921286631fa9
golang.org/x/net v0.16.0
Expand Down
Loading

0 comments on commit 34e4b58

Please sign in to comment.