github.com/hyperledger/burrow@v0.34.5-0.20220512172541-77f09336001d/integration/governance/governance_test.go (about) 1 // +build integration 2 3 package governance 4 5 import ( 6 "context" 7 "math/big" 8 "testing" 9 "time" 10 11 "github.com/hyperledger/burrow/acm" 12 "github.com/hyperledger/burrow/acm/balance" 13 "github.com/hyperledger/burrow/acm/validator" 14 "github.com/hyperledger/burrow/config" 15 "github.com/hyperledger/burrow/core" 16 "github.com/hyperledger/burrow/crypto" 17 "github.com/hyperledger/burrow/execution/errors" 18 "github.com/hyperledger/burrow/genesis/spec" 19 "github.com/hyperledger/burrow/integration" 20 "github.com/hyperledger/burrow/integration/rpctest" 21 "github.com/hyperledger/burrow/permission" 22 "github.com/hyperledger/burrow/rpc/rpcquery" 23 "github.com/hyperledger/burrow/txs/payload" 24 "github.com/stretchr/testify/assert" 25 "github.com/stretchr/testify/require" 26 tmcore "github.com/tendermint/tendermint/rpc/core" 27 "github.com/tendermint/tendermint/rpc/jsonrpc/types" 28 ) 29 30 func TestGovernance(t *testing.T) { 31 genesisAccounts := integration.MakePrivateAccounts("mysecret", 10) // make keys 32 genesisConfigs := make([]*config.BurrowConfig, len(genesisAccounts)) 33 genesisKernels := make([]*core.Kernel, len(genesisAccounts)) 34 genesisDoc := integration.TestGenesisDoc(genesisAccounts, 0) 35 genesisDoc.Accounts[4].Permissions = permission.NewAccountPermissions(permission.Send | permission.Call) 36 var err error 37 38 for i, acc := range genesisAccounts { 39 genesisConfigs[i], err = newConfig(genesisDoc, acc, genesisAccounts...) 40 require.NoError(t, err) 41 42 genesisKernels[i], err = newKernelAndBoot(genesisConfigs[i], acc, genesisAccounts...) 43 require.NoError(t, err) 44 defer integration.Shutdown(genesisKernels[i]) 45 } 46 47 time.Sleep(1 * time.Second) 48 for i := 0; i < len(genesisKernels); i++ { 49 for j := i + 1; j < len(genesisKernels); j++ { 50 connectKernels(genesisKernels[i], genesisKernels[j]) 51 } 52 } 53 54 t.Run("Group", func(t *testing.T) { 55 t.Run("AlterValidators", func(t *testing.T) { 56 inputAddress := genesisAccounts[0].GetAddress() 57 grpcAddress := genesisKernels[0].GRPCListenAddress().String() 58 tcli := rpctest.NewTransactClient(t, grpcAddress) 59 qcli := rpctest.NewQueryClient(t, grpcAddress) 60 ecli := rpctest.NewExecutionEventsClient(t, grpcAddress) 61 62 // Build a batch of validator alterations to make 63 vs := validator.NewTrimSet() 64 changePower(vs, 3, 2131) 65 changePower(vs, 2, 4561) 66 changePower(vs, 5, 7831) 67 changePower(vs, 8, 9931) 68 69 err := vs.IterateValidators(func(id crypto.Addressable, power *big.Int) error { 70 _, err := payloadSync(tcli, payload.AlterPowerTx(inputAddress, id, power.Uint64())) 71 return err 72 }) 73 require.NoError(t, err) 74 75 vsOut := getValidatorSet(t, qcli) 76 // Include the genesis validator and compare the sets 77 changePower(vs, 0, genesisDoc.Validators[0].Amount) 78 assertValidatorsEqual(t, vs, vsOut) 79 80 // Remove validator from chain 81 _, err = payloadSync(tcli, payload.AlterPowerTx(inputAddress, account(3), 0)) 82 require.NoError(t, err) 83 84 // Mirror in our check set 85 changePower(vs, 3, 0) 86 vsOut = getValidatorSet(t, qcli) 87 assertValidatorsEqual(t, vs, vsOut) 88 89 // Now check Tendermint 90 err = rpctest.WaitNBlocks(ecli, 6) 91 require.NoError(t, err) 92 height := int64(genesisKernels[0].Blockchain.LastBlockHeight()) 93 err = genesisKernels[0].Node.ConfigureRPC() 94 require.NoError(t, err) 95 tmVals, err := tmcore.Validators(&types.Context{}, &height, nil, nil) 96 require.NoError(t, err) 97 vsOut = validator.NewTrimSet() 98 99 for _, v := range tmVals.Validators { 100 publicKey, err := crypto.PublicKeyFromTendermintPubKey(v.PubKey) 101 require.NoError(t, err) 102 vsOut.ChangePower(publicKey, big.NewInt(v.VotingPower)) 103 } 104 assertValidatorsEqual(t, vs, vsOut) 105 }) 106 107 t.Run("WaitBlocks", func(t *testing.T) { 108 grpcAddress := genesisKernels[0].GRPCListenAddress().String() 109 ecli := rpctest.NewExecutionEventsClient(t, grpcAddress) 110 err := rpctest.WaitNBlocks(ecli, 2) 111 require.NoError(t, err) 112 }) 113 114 t.Run("AlterValidatorsTooQuickly", func(t *testing.T) { 115 grpcAddress := genesisKernels[0].GRPCListenAddress().String() 116 inputAddress := genesisAccounts[0].GetAddress() 117 tcli := rpctest.NewTransactClient(t, grpcAddress) 118 qcli := rpctest.NewQueryClient(t, grpcAddress) 119 120 maxFlow := getMaxFlow(t, qcli) 121 acc1 := acm.GeneratePrivateAccountFromSecret("Foo1") 122 t.Logf("Changing power of new account %v to MaxFlow = %d that should succeed", acc1.GetAddress(), maxFlow) 123 124 _, err := payloadSync(tcli, payload.AlterPowerTx(inputAddress, acc1, maxFlow)) 125 require.NoError(t, err) 126 127 maxFlow = getMaxFlow(t, qcli) 128 power := maxFlow + 1 129 acc2 := acm.GeneratePrivateAccountFromSecret("Foo2") 130 t.Logf("Changing power of new account %v to MaxFlow + 1 = %d that should fail", acc2.GetAddress(), power) 131 132 _, err = payloadSync(tcli, payload.AlterPowerTx(inputAddress, acc2, power)) 133 require.Error(t, err) 134 }) 135 136 t.Run("NoRootPermission", func(t *testing.T) { 137 grpcAddress := genesisKernels[0].GRPCListenAddress().String() 138 tcli := rpctest.NewTransactClient(t, grpcAddress) 139 // Account does not have Root permission 140 inputAddress := genesisAccounts[4].GetAddress() 141 _, err := payloadSync(tcli, payload.AlterPowerTx(inputAddress, account(5), 3433)) 142 require.Error(t, err) 143 assert.Contains(t, err.Error(), errors.PermissionDenied{Address: inputAddress, Perm: permission.Root}.Error()) 144 }) 145 146 t.Run("AlterAmount", func(t *testing.T) { 147 inputAddress := genesisAccounts[0].GetAddress() 148 grpcAddress := genesisKernels[0].GRPCListenAddress().String() 149 tcli := rpctest.NewTransactClient(t, grpcAddress) 150 qcli := rpctest.NewQueryClient(t, grpcAddress) 151 var amount uint64 = 18889 152 acc := account(5) 153 _, err := payloadSync(tcli, payload.AlterBalanceTx(inputAddress, acc, balance.New().Native(amount))) 154 require.NoError(t, err) 155 ca, err := qcli.GetAccount(context.Background(), &rpcquery.GetAccountParam{Address: acc.GetAddress()}) 156 require.NoError(t, err) 157 assert.Equal(t, amount, ca.Balance) 158 // Check we haven't altered permissions 159 assert.Equal(t, genesisDoc.Accounts[5].Permissions, ca.Permissions) 160 }) 161 162 t.Run("AlterPermissions", func(t *testing.T) { 163 inputAddress := genesisAccounts[0].GetAddress() 164 grpcAddress := genesisKernels[0].GRPCListenAddress().String() 165 tcli := rpctest.NewTransactClient(t, grpcAddress) 166 qcli := rpctest.NewQueryClient(t, grpcAddress) 167 acc := account(5) 168 _, err := payloadSync(tcli, payload.AlterPermissionsTx(inputAddress, acc, permission.Send)) 169 require.NoError(t, err) 170 ca, err := qcli.GetAccount(context.Background(), &rpcquery.GetAccountParam{Address: acc.GetAddress()}) 171 require.NoError(t, err) 172 assert.Equal(t, permission.AccountPermissions{ 173 Base: permission.BasePermissions{ 174 Perms: permission.Send, 175 SetBit: permission.Send, 176 }, 177 }, ca.Permissions) 178 }) 179 180 t.Run("CreateAccount", func(t *testing.T) { 181 inputAddress := genesisAccounts[0].GetAddress() 182 grpcAddress := genesisKernels[0].GRPCListenAddress().String() 183 tcli := rpctest.NewTransactClient(t, grpcAddress) 184 qcli := rpctest.NewQueryClient(t, grpcAddress) 185 var amount uint64 = 18889 186 acc := acm.GeneratePrivateAccountFromSecret("we almost certainly don't exist") 187 govTx := payload.AlterBalanceTx(inputAddress, acc, balance.New().Native(amount)) 188 _, err := payloadSync(tcli, govTx) 189 require.NoError(t, err) 190 ca, err := qcli.GetAccount(context.Background(), &rpcquery.GetAccountParam{Address: acc.GetAddress()}) 191 require.NoError(t, err) 192 assert.Equal(t, amount, ca.Balance) 193 }) 194 195 t.Run("ChangePowerByAddress", func(t *testing.T) { 196 // Should use the key client to look up public key 197 inputAddress := genesisAccounts[0].GetAddress() 198 grpcAddress := genesisKernels[0].GRPCListenAddress().String() 199 tcli := rpctest.NewTransactClient(t, grpcAddress) 200 201 acc := account(2) 202 address := acc.GetAddress() 203 power := uint64(2445) 204 _, err := payloadSync(tcli, payload.UpdateAccountTx(inputAddress, &spec.TemplateAccount{ 205 Address: &address, 206 Amounts: balance.New().Power(power), 207 })) 208 require.Error(t, err, "Should not be able to set power without providing public key") 209 assert.Contains(t, err.Error(), "GovTx: must be provided with public key when updating validator power") 210 }) 211 212 t.Run("InvalidSequenceNumber", func(t *testing.T) { 213 inputAddress := genesisAccounts[0].GetAddress() 214 tcli1 := rpctest.NewTransactClient(t, genesisKernels[0].GRPCListenAddress().String()) 215 tcli2 := rpctest.NewTransactClient(t, genesisKernels[4].GRPCListenAddress().String()) 216 qcli := rpctest.NewQueryClient(t, genesisKernels[0].GRPCListenAddress().String()) 217 218 acc := account(2) 219 address := acc.GetAddress() 220 publicKey := acc.GetPublicKey() 221 power := uint64(2445) 222 tx := payload.UpdateAccountTx(inputAddress, &spec.TemplateAccount{ 223 Address: &address, 224 PublicKey: publicKey, 225 Amounts: balance.New().Power(power), 226 }) 227 228 setSequence(t, qcli, tx) 229 _, err := localSignAndBroadcastSync(t, tcli1, genesisDoc.GetChainID(), genesisAccounts[0], tx) 230 require.NoError(t, err) 231 232 // Make it a different Tx hash so it can enter cache but keep sequence number 233 tx.AccountUpdates[0].Amounts = balance.New().Power(power).Native(1) 234 _, err = localSignAndBroadcastSync(t, tcli2, genesisDoc.GetChainID(), genesisAccounts[0], tx) 235 require.Error(t, err) 236 assert.Contains(t, err.Error(), "invalid sequence") 237 }) 238 }) 239 240 // tendermint AddPeer() runs asynchronously and needs to complete before we shutdown, else we get an exception like 241 // goroutine 2181 [running]: 242 // runtime/debug.Stack(0x12786c0, 0xc000085d70, 0xc000085c50) 243 // /home/sean/go1.12.1/src/runtime/debug/stack.go:24 +0x9d 244 // github.com/hyperledger/burrow/vendor/github.com/tendermint/tendermint/libs/db.(*GoLevelDB).Get(0xc005c5b318, 0xc01fd71840, 0x5, 0x8, 0x5, 0x8, 0x5) 245 // /home/sean/go/src/github.com/hyperledger/burrow/vendor/github.com/tendermint/tendermint/libs/db/go_level_db.go:57 +0xaf 246 // github.com/hyperledger/burrow/vendor/github.com/tendermint/tendermint/blockchain.(*BlockStore).LoadSeenCommit(0xc00bfd6120, 0x12, 0xc002b85c90) 247 // /home/sean/go/src/github.com/hyperledger/burrow/vendor/github.com/tendermint/tendermint/blockchain/store.go:128 +0xf2 248 // github.com/hyperledger/burrow/vendor/github.com/tendermint/tendermint/consensus.(*ConsensusState).LoadCommit(0xc002b85c00, 0x12, 0x0) 249 // /home/sean/go/src/github.com/hyperledger/burrow/vendor/github.com/tendermint/tendermint/consensus/state.go:273 +0xb2 250 // github.com/hyperledger/burrow/vendor/github.com/tendermint/tendermint/consensus.(*ConsensusReactor).queryMaj23Routine(0xc0008ec680, 0x12ad1a0, 0xc010f79800, 0xc009119520) 251 // /home/sean/go/src/github.com/hyperledger/burrow/vendor/github.com/tendermint/tendermint/consensus/reactor.go:789 +0x291 252 // created by github.com/hyperledger/burrow/vendor/github.com/tendermint/tendermint/consensus.(*ConsensusReactor).AddPeer 253 // /home/sean/go/src/github.com/hyperledger/burrow/vendor/github.com/tendermint/tendermint/consensus/reactor.go:171 +0x23a 254 255 time.Sleep(20 * time.Second) 256 }