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

tools: Allow specification of Reward Pool Account Balance in Genesis #4643

Merged
merged 23 commits into from
Nov 1, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
2acacdb
tmp
barnjamin Oct 14, 2022
1eaef62
set balance to 0
barnjamin Oct 14, 2022
d79453e
set alloc
barnjamin Oct 14, 2022
9f18a01
Try min bal
barnjamin Oct 14, 2022
21508a1
set reward pool to min allocation when in dev mode
barnjamin Oct 14, 2022
345c99d
dont define reward pool as zero address
barnjamin Oct 14, 2022
305e1e1
adding another flag to the gen.GenesisData struct to allow more exact…
barnjamin Oct 19, 2022
917f547
Merge branch 'master' into devmode-no-rewards
barnjamin Oct 19, 2022
6441788
Merge branch 'master' into devmode-genesis-no-reward
barnjamin Oct 19, 2022
5b428a8
fix part key assignement
barnjamin Oct 19, 2022
d4d1cfe
rename flag to make it clear this is just an initial condition
barnjamin Oct 25, 2022
80f3ce0
remove flag from create, add field to genesis template for rewards po…
barnjamin Oct 27, 2022
2812d89
fix possible bug with balance between 0 and min bal
barnjamin Oct 27, 2022
1bae82b
Update gen/generate.go
barnjamin Oct 27, 2022
ceff9e5
Add tests confirming genesis.json generation
michaeldiamant Oct 28, 2022
075711f
Fix comment
michaeldiamant Oct 28, 2022
7cea01f
Fix reviewdog errors
michaeldiamant Oct 28, 2022
99c7c8c
Merge pull request #1 from michaeldiamant/TestGenesisJsonCreation
barnjamin Oct 31, 2022
cd39c5e
Update netdeploy/network.go
barnjamin Oct 31, 2022
019df3e
Update gen/generate.go
michaeldiamant Nov 1, 2022
5193c93
group imports
barnjamin Nov 1, 2022
0c3ec98
Merge branch 'devmode-no-rewards' into devmode-genesis-no-reward
barnjamin Nov 1, 2022
d4db850
remove unintended merge changes
barnjamin Nov 1, 2022
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
41 changes: 29 additions & 12 deletions gen/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,14 +149,28 @@ func GenerateGenesisFiles(genesisData GenesisData, consensus config.ConsensusPro
return fmt.Errorf("couldn't make output directory '%s': %v", outDir, err.Error())
}

return generateGenesisFiles(outDir, proto, consensusParams, genesisData.NetworkName, genesisData.VersionModifier, allocation, genesisData.FirstPartKeyRound, genesisData.LastPartKeyRound, genesisData.PartKeyDilution, genesisData.FeeSink, genesisData.RewardsPool, genesisData.Comment, genesisData.DevMode, verboseOut)
return generateGenesisFiles(
proto, consensusParams, allocation, genesisData, outDir, verboseOut,
)
}

func generateGenesisFiles(outDir string, protoVersion protocol.ConsensusVersion, protoParams config.ConsensusParams, netName string, schemaVersionModifier string,
allocation []genesisAllocation, firstWalletValid uint64, lastWalletValid uint64, partKeyDilution uint64, feeSink, rewardsPool basics.Address, comment string, devmode bool, verboseOut io.Writer) (err error) {
func generateGenesisFiles(protoVersion protocol.ConsensusVersion, protoParams config.ConsensusParams, allocation []genesisAllocation, genData GenesisData, outDir string, verboseOut io.Writer) (err error) {

genesisAddrs := make(map[string]basics.Address)
records := make(map[string]basics.AccountData)
var (
netName = genData.NetworkName
schemaVersionModifier = genData.VersionModifier
firstWalletValid = genData.FirstPartKeyRound
lastWalletValid = genData.LastPartKeyRound
partKeyDilution = genData.PartKeyDilution
feeSink = genData.FeeSink
rewardsPool = genData.RewardsPool
devmode = genData.DevMode
rewardsBalance = genData.RewardsPoolBalance
comment = genData.Comment

genesisAddrs = make(map[string]basics.Address)
records = make(map[string]basics.AccountData)
)

if partKeyDilution == 0 {
partKeyDilution = protoParams.DefaultKeyDilution
Expand Down Expand Up @@ -326,24 +340,27 @@ func generateGenesisFiles(outDir string, protoVersion protocol.ConsensusVersion,
fmt.Fprintln(verboseOut, protoVersion, protoParams.MinBalance)
}

if rewardsBalance < protoParams.MinBalance {
michaeldiamant marked this conversation as resolved.
Show resolved Hide resolved
// Needs to at least have min balance
rewardsBalance = protoParams.MinBalance
michaeldiamant marked this conversation as resolved.
Show resolved Hide resolved
}
barnjamin marked this conversation as resolved.
Show resolved Hide resolved

records["FeeSink"] = basics.AccountData{
Status: basics.NotParticipating,
MicroAlgos: basics.MicroAlgos{Raw: protoParams.MinBalance},
}

records["RewardsPool"] = basics.AccountData{
Status: basics.NotParticipating,
MicroAlgos: basics.MicroAlgos{Raw: defaultIncentivePoolBalanceAtInception},
MicroAlgos: basics.MicroAlgos{Raw: rewardsBalance},
}

// Add FeeSink and RewardsPool to allocation slice to be handled with other allocations.
sinkAcct := genesisAllocation{
michaeldiamant marked this conversation as resolved.
Show resolved Hide resolved
Name: "FeeSink",
Stake: protoParams.MinBalance,
barnjamin marked this conversation as resolved.
Show resolved Hide resolved
Online: basics.NotParticipating,
Name: "FeeSink",
}
poolAcct := genesisAllocation{
Name: "RewardsPool",
Stake: defaultIncentivePoolBalanceAtInception,
Online: basics.NotParticipating,
Name: "RewardsPool",
}
winder marked this conversation as resolved.
Show resolved Hide resolved

alloc2 := make([]genesisAllocation, 0, len(allocation)+2)
Expand Down
125 changes: 122 additions & 3 deletions gen/generate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,25 @@
package gen

import (
"encoding/json"
"fmt"
"io"
"os"
"path/filepath"
"strings"
"sync"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/algorand/go-algorand/config"
"github.com/algorand/go-algorand/crypto"
"github.com/algorand/go-algorand/data/account"
"github.com/algorand/go-algorand/data/bookkeeping"
"github.com/algorand/go-algorand/protocol"
"github.com/algorand/go-algorand/util/db"

"github.com/algorand/go-algorand/test/partitiontest"
"github.com/stretchr/testify/require"
"github.com/algorand/go-algorand/util/db"
)

func TestLoadMultiRootKeyConcurrent(t *testing.T) {
Expand Down Expand Up @@ -114,3 +120,116 @@ func TestGenesisRoundoff(t *testing.T) {
require.NoError(t, err)
require.True(t, strings.Contains(verbosity.String(), "roundoff"))
}

// `TestGenesisJsonCreation` defends against regressions to `genesis.json` generation by comparing a known, valid `genesis.json` against a version generated during test invocation.
//
// * For each `testCase`, there is a corresponding `genesis.json` in `gen/resources` representing the known, valid output.
// * When adding test cases, it's assumed folks peer review new artifacts in `gen/resources`.
// * Since _some_ `genesis.json` values are non-deterministic, the test replaces these values with static values to facilitate equality checks.
func TestGenesisJsonCreation(t *testing.T) {
partitiontest.PartitionTest(t)
t.Parallel()

type testCase struct {
name string
gd GenesisData
}

// `base` is a canonical test confirming `devnet.json` generates the intended `genesis.json`.
base := func() testCase {
jsonBytes, err := os.ReadFile("devnet.json")
require.NoError(t, err)

gd := DefaultGenesis
err = json.Unmarshal(jsonBytes, &gd)
require.NoError(t, err)

return testCase{"base", gd}
}

// `balance` extends `base` to confirm overriding the rewards pool balance works.
balance := func() testCase {
gd := base().gd
gd.RewardsPoolBalance = 0 // Expect generated balance == MinBalance
return testCase{"balance", gd}
}

// `blotOutRandomValues` replaces random values with static values to support equality checks.
blotOutRandomValues := func(as []bookkeeping.GenesisAllocation) {
deterministicAddresses := []string{"FeeSink", "RewardsPool"}

isNondeterministicAddress := func(name string) bool {
for _, address := range deterministicAddresses {
if name == address {
return false
}
}
return true
}

for i := range as {
require.Len(t, as[i].State.VoteID, 32)
as[i].State.VoteID = crypto.OneTimeSignatureVerifier{}
require.Len(t, as[i].State.VoteID, 32)
as[i].State.SelectionID = crypto.VRFVerifier{}

if isNondeterministicAddress(as[i].Comment) {
require.Len(t, as[i].Address, 58)
as[i].Address = ""
}
}
}

saveGeneratedGenesisJSON := func(filename, artifactName string) {
src, err := os.Open(filename)
require.NoError(t, err)
defer src.Close()

dst, err := os.CreateTemp("", "*-"+artifactName)
require.NoError(t, err)
defer dst.Close()

_, err = io.Copy(dst, src)
require.NoError(t, err)

t.Log("generated genesis.json = " + dst.Name())
}

// Since `t.TempDir` deletes the generated dir, retain generated `genesis.json` on test failure.
saveOnFailure := func(result bool, generatedFilename, artifactName string) {
if !result {
saveGeneratedGenesisJSON(generatedFilename, artifactName)
t.FailNow()
}
}

for _, tc := range []testCase{
base(),
balance(),
} {
t.Run(fmt.Sprintf("name=%v", tc.name), func(t *testing.T) {
gd := tc.gd
gd.LastPartKeyRound = 10 // Ensure quick test execution by reducing rounds.

outDir := t.TempDir()
err := GenerateGenesisFiles(gd, config.Consensus, outDir, nil)
require.NoError(t, err)

artifactName := fmt.Sprintf("genesis-%v.json", tc.name)
generatedFilename := fmt.Sprintf("%v/genesis.json", outDir)
saveOnFailure := func(result bool) {
saveOnFailure(result, generatedFilename, artifactName)
}

roundtrip, err := bookkeeping.LoadGenesisFromFile(generatedFilename)
require.NoError(t, err)

expected, err := bookkeeping.LoadGenesisFromFile("resources/" + artifactName)
saveOnFailure(assert.NoError(t, err))

blotOutRandomValues(expected.Allocation)
blotOutRandomValues(roundtrip.Allocation)
saveOnFailure(assert.Equal(t, expected, roundtrip))
})
}
}
Loading