Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

soft fork: implement a way to change the circuit of a chain #1205

Merged
merged 5 commits into from
Dec 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 14 additions & 14 deletions api/api_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -200,20 +200,20 @@ type GenericTransactionWithInfo struct {
}

type ChainInfo struct {
ID string `json:"chainId" example:"azeno"`
BlockTime [5]uint64 `json:"blockTime" example:"12000,11580,11000,11100,11100"`
ElectionCount uint64 `json:"electionCount" example:"120"`
OrganizationCount uint64 `json:"organizationCount" example:"20"`
GenesisTime time.Time `json:"genesisTime" format:"date-time" example:"2022-11-17T18:00:57.379551614Z"`
Height uint32 `json:"height" example:"5467"`
Syncing bool `json:"syncing" example:"true"`
Timestamp int64 `json:"blockTimestamp" swaggertype:"string" format:"date-time" example:"2022-11-17T18:00:57.379551614Z"`
TransactionCount uint64 `json:"transactionCount" example:"554"`
ValidatorCount uint32 `json:"validatorCount" example:"5"`
VoteCount uint64 `json:"voteCount" example:"432"`
CircuitConfigurationTag string `json:"cicuitConfigurationTag" example:"dev"`
MaxCensusSize uint64 `json:"maxCensusSize" example:"50000"`
NetworkCapacity uint64 `json:"networkCapacity" example:"2000"`
ID string `json:"chainId" example:"azeno"`
BlockTime [5]uint64 `json:"blockTime" example:"12000,11580,11000,11100,11100"`
ElectionCount uint64 `json:"electionCount" example:"120"`
OrganizationCount uint64 `json:"organizationCount" example:"20"`
GenesisTime time.Time `json:"genesisTime" format:"date-time" example:"2022-11-17T18:00:57.379551614Z"`
Height uint32 `json:"height" example:"5467"`
Syncing bool `json:"syncing" example:"true"`
Timestamp int64 `json:"blockTimestamp" swaggertype:"string" format:"date-time" example:"2022-11-17T18:00:57.379551614Z"`
TransactionCount uint64 `json:"transactionCount" example:"554"`
ValidatorCount uint32 `json:"validatorCount" example:"5"`
VoteCount uint64 `json:"voteCount" example:"432"`
CircuitVersion string `json:"circuitVersion" example:"v1.0.0"`
MaxCensusSize uint64 `json:"maxCensusSize" example:"50000"`
NetworkCapacity uint64 `json:"networkCapacity" example:"2000"`
}

type Account struct {
Expand Down
9 changes: 2 additions & 7 deletions api/censuses.go
Original file line number Diff line number Diff line change
Expand Up @@ -209,14 +209,9 @@ func (a *API) censusCreateHandler(msg *apirest.APIdata, ctx *httprouter.HTTPCont
return ErrCensusTypeUnknown
}

// get census max levels from vochain app if available
maxLevels := circuit.CircuitsConfigurations[circuit.DefaultCircuitConfigurationTag].Levels
if a.vocapp != nil {
maxLevels = a.vocapp.TransactionHandler.ZkCircuit.Config.Levels
}

// census max levels is limited by global ZkCircuit Levels
censusID := util.RandomBytes(32)
_, err = a.censusdb.New(censusID, censusType, "", &token, maxLevels)
_, err = a.censusdb.New(censusID, censusType, "", &token, circuit.Global().Config.Levels)
if err != nil {
return err
}
Expand Down
36 changes: 17 additions & 19 deletions api/chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -301,20 +301,20 @@ func (a *API) chainInfoHandler(_ *apirest.APIdata, ctx *httprouter.HTTPContext)
}

data, err := json.Marshal(&ChainInfo{
ID: a.vocapp.ChainID(),
BlockTime: a.vocinfo.BlockTimes(),
ElectionCount: a.indexer.CountTotalProcesses(),
OrganizationCount: a.indexer.CountTotalEntities(),
Height: a.vocapp.Height(),
Syncing: a.vocapp.IsSynchronizing(),
TransactionCount: transactionCount,
ValidatorCount: uint32(len(validators)),
Timestamp: a.vocapp.Timestamp(),
VoteCount: voteCount,
GenesisTime: a.vocapp.Genesis().GenesisTime,
CircuitConfigurationTag: a.vocapp.CircuitConfigurationTag(),
MaxCensusSize: maxCensusSize,
NetworkCapacity: networkCapacity,
ID: a.vocapp.ChainID(),
BlockTime: a.vocinfo.BlockTimes(),
ElectionCount: a.indexer.CountTotalProcesses(),
OrganizationCount: a.indexer.CountTotalEntities(),
Height: a.vocapp.Height(),
Syncing: a.vocapp.IsSynchronizing(),
TransactionCount: transactionCount,
ValidatorCount: uint32(len(validators)),
Timestamp: a.vocapp.Timestamp(),
VoteCount: voteCount,
GenesisTime: a.vocapp.Genesis().GenesisTime,
CircuitVersion: circuit.Version(),
MaxCensusSize: maxCensusSize,
NetworkCapacity: networkCapacity,
})
if err != nil {
return err
Expand All @@ -329,13 +329,11 @@ func (a *API) chainInfoHandler(_ *apirest.APIdata, ctx *httprouter.HTTPContext)
// @Tags Chain
// @Accept json
// @Produce json
// @Success 200 {object} circuit.ZkCircuitConfig
// @Success 200 {object} circuit.Config
// @Router /chain/info/circuit [get]
func (a *API) chainCircuitInfoHandler(_ *apirest.APIdata, ctx *httprouter.HTTPContext) error {
// Get current circuit tag
circuitConfig := circuit.GetCircuitConfiguration(a.vocapp.CircuitConfigurationTag())
// Encode the circuit configuration to JSON
data, err := json.Marshal(circuitConfig)
// Encode the current circuit configuration to JSON
data, err := json.Marshal(circuit.Global().Config)
if err != nil {
return err
}
Expand Down
9 changes: 6 additions & 3 deletions apiclient/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ type HTTPclient struct {
addr *url.URL
account *ethereum.SignKeys
chainID string
circuit *circuit.ZkCircuitConfig
circuit *circuit.ZkCircuit
retries int
}

Expand Down Expand Up @@ -72,8 +72,11 @@ func NewHTTPclient(addr *url.URL, bearerToken *uuid.UUID) (*HTTPclient, error) {
return nil, fmt.Errorf("cannot get chain ID from API server")
}
c.chainID = info.ID
// Get the default circuit config
c.circuit = circuit.GetCircuitConfiguration(info.CircuitConfigurationTag)

c.circuit, err = circuit.LoadVersion(info.CircuitVersion)
if err != nil {
return nil, fmt.Errorf("error loading circuit: %w", err)
}
return c, nil
}

Expand Down
10 changes: 2 additions & 8 deletions apiclient/vote.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package apiclient

import (
"context"
"encoding/hex"
"encoding/json"
"fmt"
Expand Down Expand Up @@ -102,14 +101,9 @@ func (cl *HTTPclient) Vote(v *VoteData) (types.HexBytes, error) {
if err != nil {
return nil, fmt.Errorf("error encoding inputs: %w", err)
}
// load the correct circuit from the ApiClient configuration
currentCircuit, err := circuit.LoadZkCircuit(context.Background(), c.circuit)
if err != nil {
return nil, fmt.Errorf("error loading circuit: %w", err)
}
// instance the prover with the circuit config loaded and generate the
// proof for the calculated inputs
proof, err := prover.Prove(currentCircuit.ProvingKey, currentCircuit.Wasm, inputs)
proof, err := prover.Prove(c.circuit.ProvingKey, c.circuit.Wasm, inputs)
if err != nil {
return nil, fmt.Errorf("could not generate anonymous proof: %w", err)
}
Expand All @@ -119,7 +113,7 @@ func (cl *HTTPclient) Vote(v *VoteData) (types.HexBytes, error) {
return nil, err
}
// include vote nullifier and the encoded proof in a VoteEnvelope
nullifier, err := proof.Nullifier()
nullifier, err := proof.ExtractPubSignal("nullifier")
if err != nil {
return nil, err
}
Expand Down
2 changes: 1 addition & 1 deletion benchmark/zk_census_benchmark_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ func genProofZk(b *testing.B, electionID []byte, acc *ethereum.SignKeys, censusD
"nullifier", nullifier.String())

// Get artifacts of the current circuit
currentCircuit, err := circuit.LoadZkCircuit(context.Background(), zkCircuitTest)
currentCircuit, err := circuit.LoadConfig(context.Background(), zkCircuitTest)
qt.Assert(b, err, qt.IsNil)
// Calculate the proof for the current apiclient circuit config and the
// inputs encoded.
Expand Down
16 changes: 8 additions & 8 deletions cmd/node/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,8 @@ func newConfig() (*config.Config, config.Error) {
"directory where data is stored")
flag.StringVarP(&conf.Vochain.DBType, "dbType", "t", db.TypePebble,
fmt.Sprintf("key-value db type [%s,%s,%s]", db.TypePebble, db.TypeLevelDB, db.TypeMongo))
flag.StringVarP(&conf.Vochain.Chain, "chain", "c", "dev",
fmt.Sprintf("vocdoni blockchain to connect with: %q", genesis.AvailableChains()))
flag.StringVarP(&conf.Vochain.Network, "chain", "c", "dev",
fmt.Sprintf("vocdoni network to connect with: %q", genesis.AvailableNetworks()))
flag.BoolVar(&conf.Dev, "dev", false,
"use developer mode (less security)")
conf.PprofPort = *flag.Int("pprof", 0,
Expand Down Expand Up @@ -181,7 +181,7 @@ func newConfig() (*config.Config, config.Error) {
if err = viper.BindPFlag("chain", flag.Lookup("chain")); err != nil {
log.Fatalf("failed to bind chain flag to viper: %v", err)
}
conf.Vochain.Chain = viper.GetString("chain")
conf.Vochain.Network = viper.GetString("chain")

if err = viper.BindPFlag("dev", flag.Lookup("dev")); err != nil {
log.Fatalf("failed to bind dev flag to viper: %v", err)
Expand All @@ -197,8 +197,8 @@ func newConfig() (*config.Config, config.Error) {
}
conf.Vochain.DBType = viper.GetString("dbType")

// use different datadirs for different chains
conf.DataDir = filepath.Join(conf.DataDir, conf.Vochain.Chain)
// use different datadirs for different networks
conf.DataDir = filepath.Join(conf.DataDir, conf.Vochain.Network)

if err = viper.BindPFlag("archiveURL", flag.Lookup("archiveURL")); err != nil {
log.Fatalf("failed to bind archiveURL flag to viper: %v", err)
Expand Down Expand Up @@ -478,7 +478,7 @@ func main() {
}()
}
log.Infow("starting vocdoni node", "version", internal.Version, "mode", conf.Mode,
"chain", conf.Vochain.Chain, "dbType", conf.Vochain.DBType)
"network", conf.Vochain.Network, "dbType", conf.Vochain.DBType)
if conf.Dev {
log.Warn("developer mode is enabled!")
}
Expand Down Expand Up @@ -517,8 +517,8 @@ func main() {
srv.Config.TendermintMetrics = true
srv.Router.ExposePrometheusEndpoint("/metrics")

metrics.NewCounter(fmt.Sprintf("vocdoni_info{version=%q,mode=%q,chain=%q}",
internal.Version, conf.Mode, conf.Vochain.Chain)).Set(1)
metrics.NewCounter(fmt.Sprintf("vocdoni_info{version=%q,mode=%q,network=%q}",
internal.Version, conf.Mode, conf.Vochain.Network)).Set(1)
}
}

Expand Down
6 changes: 3 additions & 3 deletions cmd/vochaininspector/inspector.go
Original file line number Diff line number Diff line change
Expand Up @@ -170,9 +170,9 @@ func main() {
}
}

func newVochain(chain, dataDir string) *vochain.BaseApplication {
func newVochain(network, dataDir string) *vochain.BaseApplication {
cfg := &config.VochainCfg{
Chain: chain,
Network: network,
Dev: true,
LogLevel: "error",
DataDir: dataDir,
Expand All @@ -192,7 +192,7 @@ func newVochain(chain, dataDir string) *vochain.BaseApplication {
}
log.Infof("external ip address %s", cfg.PublicAddr)
// Create the vochain node
genesisBytes := genesis.Genesis[chain].Genesis.Marshal()
genesisBytes := genesis.Genesis[network].Genesis.Marshal()
return vochain.NewVochain(cfg, genesisBytes)
}

Expand Down
4 changes: 2 additions & 2 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,8 @@ type IPFSCfg struct {

// VochainCfg includes all possible config params needed by the Vochain
type VochainCfg struct {
// Chain is the network name to connect with
Chain string
// Network is the network name to connect with
Network string
// Dev indicates we use the Vochain development mode (low security is accepted)
Dev bool
// LogLevel logging level for tendermint
Expand Down
27 changes: 27 additions & 0 deletions config/forks.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package config

// ForksCfg allows applying softforks at specified heights
type ForksCfg struct {
VoceremonyForkBlock uint32
}

// Forks is a map of chainIDs
var Forks = map[string]*ForksCfg{
"vocdoni/DEV/29": {
VoceremonyForkBlock: 217200, // estimated 2023-12-05T11:33:31.426638381Z
},
"vocdoni/STAGE/9": {
VoceremonyForkBlock: 247000, // estimated 2023-12-11T08:47:56.552083308Z
},
"vocdoni/LTS/1.2": {
VoceremonyForkBlock: 393000, // estimated 2023-12-11T11:51:47.046130989Z
},
}

// ForksForChainID returns the ForksCfg of chainID, if found, or an empty ForksCfg otherwise
func ForksForChainID(chainID string) *ForksCfg {
if cfg, found := Forks[chainID]; found {
return cfg
}
return &ForksCfg{}
}
12 changes: 6 additions & 6 deletions crypto/ethereum/vocdoni_sik.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import (
"math/big"

"github.com/iden3/go-iden3-crypto/poseidon"
"go.vocdoni.io/dvote/crypto/zk"
"go.vocdoni.io/dvote/tree/arbo"
"go.vocdoni.io/dvote/util"
)

// SIKsignature signs the default vocdoni sik payload. It envolves the
Expand Down Expand Up @@ -38,8 +38,8 @@ func (k *SignKeys) AccountSIK(secret []byte) ([]byte, error) {
}
seed := []*big.Int{
arbo.BytesToBigInt(k.Address().Bytes()),
zk.BigToFF(new(big.Int).SetBytes(secret)),
zk.BigToFF(new(big.Int).SetBytes(sign)),
util.BigToFF(new(big.Int).SetBytes(secret)),
util.BigToFF(new(big.Int).SetBytes(sign)),
}
hash, err := poseidon.Hash(seed)
if err != nil {
Expand All @@ -58,14 +58,14 @@ func (k *SignKeys) AccountSIKnullifier(electionID, secret []byte) ([]byte, error
}
// get the representation of the signature on the finite field and repeat
// the same with the secret if it is provided, if not add a zero
seed := []*big.Int{zk.BigToFF(new(big.Int).SetBytes(sign))}
seed := []*big.Int{util.BigToFF(new(big.Int).SetBytes(sign))}
if secret != nil {
seed = append(seed, zk.BigToFF(new(big.Int).SetBytes(secret)))
seed = append(seed, util.BigToFF(new(big.Int).SetBytes(secret)))
} else {
seed = append(seed, big.NewInt(0))
}
// encode the election id for circom and include it into the nullifier
seed = append(seed, zk.BytesToArbo(electionID)...)
seed = append(seed, util.BytesToArbo(electionID)...)
// calculate the poseidon image --> H(signature + secret + electionId)
hash, err := poseidon.Hash(seed)
if err != nil {
Expand Down
Loading