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  }