github.com/hyperledger/burrow@v0.34.5-0.20220512172541-77f09336001d/integration/governance/bonding_test.go (about) 1 // +build integration 2 3 package governance 4 5 import ( 6 "bytes" 7 "testing" 8 9 "github.com/hyperledger/burrow/bcm" 10 "github.com/hyperledger/burrow/config" 11 "github.com/hyperledger/burrow/core" 12 "github.com/hyperledger/burrow/integration" 13 "github.com/hyperledger/burrow/integration/rpctest" 14 "github.com/hyperledger/burrow/permission" 15 "github.com/hyperledger/burrow/txs/payload" 16 "github.com/stretchr/testify/require" 17 ) 18 19 func TestBonding(t *testing.T) { 20 genesisAccounts := integration.MakePrivateAccounts("accounts", 6) 21 genesisConfigs := make([]*config.BurrowConfig, len(genesisAccounts)) 22 genesisKernels := make([]*core.Kernel, len(genesisAccounts)) 23 genesisDoc := integration.TestGenesisDoc(genesisAccounts, 0, 1, 2, 3) 24 genesisDoc.GlobalPermissions = permission.NewAccountPermissions(permission.Input) 25 genesisDoc.Accounts[4].Permissions = permission.ZeroAccountPermissions.Clone() 26 var err error 27 28 // we need at least one validator to start 29 for i, acc := range genesisAccounts { 30 genesisConfigs[i], err = newConfig(genesisDoc, acc, genesisAccounts...) 31 require.NoError(t, err) 32 33 genesisKernels[i], err = newKernelAndBoot(genesisConfigs[i], acc, genesisAccounts...) 34 require.NoError(t, err) 35 defer integration.Shutdown(genesisKernels[i]) 36 } 37 38 connectAllKernels(genesisKernels) 39 40 t.Run("NoPermission", func(t *testing.T) { 41 localAddress := genesisKernels[4].GRPCListenAddress().String() 42 inputAccount := genesisAccounts[4].GetAddress() 43 tcli := rpctest.NewTransactClient(t, localAddress) 44 bondTx := payload.NewBondTx(inputAccount, uint64(1<<2)) 45 _, err = payloadSync(tcli, bondTx) 46 require.Error(t, err) 47 }) 48 49 t.Run("BondFromNonVal", func(t *testing.T) { 50 // lets do the bond tx from a non-validator node 51 valAccount := genesisAccounts[5] 52 valKernel := genesisKernels[5] 53 54 localAddress := valKernel.GRPCListenAddress().String() 55 inputAccount := valAccount.GetAddress() 56 tcli := rpctest.NewTransactClient(t, localAddress) 57 qcli := rpctest.NewQueryClient(t, localAddress) 58 59 accBefore := getAccount(t, qcli, inputAccount) 60 var power uint64 = 1 << 16 61 62 bondTx := payload.NewBondTx(inputAccount, power) 63 _, err = payloadSync(tcli, bondTx) 64 require.NoError(t, err) 65 accAfter := getAccount(t, qcli, inputAccount) 66 // ensure power is subtracted from original account balance 67 require.Equal(t, accBefore.GetBalance()-power, accAfter.GetBalance()) 68 69 // make sure our new validator exists in the set 70 vsOut := getValidators(t, qcli) 71 require.Contains(t, vsOut, valAccount.GetAddress()) 72 require.Equal(t, vsOut[valAccount.GetAddress()].GetPower(), power) 73 74 // wait for new validator to see themself in set 75 waitFor(3, valKernel.Blockchain) 76 vsOut = getValidators(t, qcli) 77 require.Contains(t, vsOut, valAccount.GetAddress()) 78 require.Equal(t, vsOut[valAccount.GetAddress()].GetPower(), power) 79 80 // wait for validator to propose a block 81 waitFor(10, valKernel.Blockchain) 82 checkProposed(t, genesisKernels[0], valAccount.GetPublicKey().GetAddress().Bytes()) 83 84 unbondTx := payload.NewUnbondTx(inputAccount, power) 85 _, err = payloadSync(tcli, unbondTx) 86 require.NoError(t, err) 87 88 waitFor(2, valKernel.Blockchain) 89 vsOut = getValidators(t, qcli) 90 require.NotContains(t, vsOut, valAccount.GetAddress()) 91 accAfter = getAccount(t, qcli, inputAccount) 92 require.Equal(t, accBefore.GetBalance(), accAfter.GetBalance()) 93 }) 94 95 // TODO: 96 // - add / remove too quickly 97 // - only validator can unbond themselves 98 } 99 100 func checkProposed(t *testing.T, kern *core.Kernel, exp []byte) { 101 height := kern.Node.BlockStore().Height() 102 t.Logf("current height is %d", height) 103 for i := int64(1); i < height; i++ { 104 bm := kern.Node.BlockStore().LoadBlockMeta(i) 105 if bytes.Equal(bm.Header.ProposerAddress, exp) { 106 t.Logf("%X proposed block %d", exp, i) 107 return 108 } 109 } 110 require.Fail(t, "bonded validator did not propose any blocks") 111 } 112 113 func waitFor(height uint64, blockchain *bcm.Blockchain) { 114 until := blockchain.LastBlockHeight() + height 115 for h := uint64(0); h < until; h = blockchain.LastBlockHeight() { 116 continue 117 } 118 }