From d1caf63384dca325e665bbe51a3b94c13f091b25 Mon Sep 17 00:00:00 2001 From: Warren He Date: Thu, 13 Feb 2020 15:46:29 -0800 Subject: [PATCH 1/2] go staking: add per-account lockup --- .../tendermint/apps/staking/transactions.go | 19 +++++-- .../apps/staking/transactions_test.go | 50 ++++++++++++++++++- go/staking/api/api.go | 5 +- 3 files changed, 66 insertions(+), 8 deletions(-) diff --git a/go/consensus/tendermint/apps/staking/transactions.go b/go/consensus/tendermint/apps/staking/transactions.go index 6b4e4fb7bcd..7538c395557 100644 --- a/go/consensus/tendermint/apps/staking/transactions.go +++ b/go/consensus/tendermint/apps/staking/transactions.go @@ -1,16 +1,19 @@ package staking import ( + "fmt" + "github.com/oasislabs/oasis-core/go/common/cbor" "github.com/oasislabs/oasis-core/go/common/crypto/signature" "github.com/oasislabs/oasis-core/go/common/quantity" "github.com/oasislabs/oasis-core/go/consensus/tendermint/abci" "github.com/oasislabs/oasis-core/go/consensus/tendermint/api" stakingState "github.com/oasislabs/oasis-core/go/consensus/tendermint/apps/staking/state" + epochtime "github.com/oasislabs/oasis-core/go/epochtime/api" staking "github.com/oasislabs/oasis-core/go/staking/api" ) -func isTransferPermitted(params *staking.ConsensusParameters, fromID signature.PublicKey) (permitted bool) { +func isTransferPermitted(params *staking.ConsensusParameters, fromID signature.PublicKey, from *staking.Account, epoch epochtime.EpochTime) (permitted bool) { permitted = true if params.DisableTransfers { permitted = false @@ -18,6 +21,9 @@ func isTransferPermitted(params *staking.ConsensusParameters, fromID signature.P permitted = true } } + if epoch < from.General.TransfersNotBefore { + permitted = false + } return } @@ -31,16 +37,19 @@ func (app *stakingApplication) transfer(ctx *abci.Context, state *stakingState.M if err != nil { return err } - if err := ctx.Gas().UseGas(1, staking.GasOpTransfer, params.GasCosts); err != nil { + if err = ctx.Gas().UseGas(1, staking.GasOpTransfer, params.GasCosts); err != nil { return err } fromID := ctx.TxSigner() - if !isTransferPermitted(params, fromID) { - return staking.ErrForbidden + epoch, err := app.state.GetCurrentEpoch(ctx.Ctx()) + if err != nil { + return fmt.Errorf("getting current epoch: %w", err) } - from := state.Account(fromID) + if !isTransferPermitted(params, fromID, from, epoch) { + return staking.ErrForbidden + } if fromID.Equal(xfer.To) { // Handle transfer to self as just a balance check. diff --git a/go/consensus/tendermint/apps/staking/transactions_test.go b/go/consensus/tendermint/apps/staking/transactions_test.go index e1f75f5f64b..ee3a5534934 100644 --- a/go/consensus/tendermint/apps/staking/transactions_test.go +++ b/go/consensus/tendermint/apps/staking/transactions_test.go @@ -6,6 +6,7 @@ import ( "github.com/stretchr/testify/require" "github.com/oasislabs/oasis-core/go/common/crypto/signature" + epochtime "github.com/oasislabs/oasis-core/go/epochtime/api" staking "github.com/oasislabs/oasis-core/go/staking/api" ) @@ -14,12 +15,16 @@ func TestIsTransferPermitted(t *testing.T) { msg string params *staking.ConsensusParameters fromID signature.PublicKey + from *staking.Account + epoch epochtime.EpochTime permitted bool }{ { "no disablement", &staking.ConsensusParameters{}, signature.PublicKey{}, + &staking.Account{}, + 0, true, }, { @@ -28,6 +33,8 @@ func TestIsTransferPermitted(t *testing.T) { DisableTransfers: true, }, signature.PublicKey{}, + &staking.Account{}, + 0, false, }, { @@ -39,6 +46,8 @@ func TestIsTransferPermitted(t *testing.T) { }, }, signature.PublicKey{}, + &staking.Account{}, + 0, false, }, { @@ -50,9 +59,48 @@ func TestIsTransferPermitted(t *testing.T) { }, }, signature.PublicKey{}, + &staking.Account{}, + 0, true, }, + { + "before allowed", + &staking.ConsensusParameters{}, + signature.PublicKey{}, + &staking.Account{ + General: staking.GeneralAccount{ + TransfersNotBefore: 1, + }, + }, + 0, + false, + }, + { + "after allowed", + &staking.ConsensusParameters{}, + signature.PublicKey{}, + &staking.Account{}, + 1, + true, + }, + { + "whitelisted before allowed ", + &staking.ConsensusParameters{ + DisableTransfers: true, + UndisableTransfersFrom: map[signature.PublicKey]bool{ + signature.PublicKey{}: true, + }, + }, + signature.PublicKey{}, + &staking.Account{ + General: staking.GeneralAccount{ + TransfersNotBefore: 1, + }, + }, + 0, + false, + }, } { - require.Equal(t, tt.permitted, isTransferPermitted(tt.params, tt.fromID), tt.msg) + require.Equal(t, tt.permitted, isTransferPermitted(tt.params, tt.fromID, tt.from, tt.epoch), tt.msg) } } diff --git a/go/staking/api/api.go b/go/staking/api/api.go index 6c725f3ad07..128376493ab 100644 --- a/go/staking/api/api.go +++ b/go/staking/api/api.go @@ -414,8 +414,9 @@ func (sa *StakeAccumulator) TotalClaims(thresholds map[ThresholdKind]quantity.Qu // GeneralAccount is a general-purpose account. type GeneralAccount struct { - Balance quantity.Quantity `json:"balance"` - Nonce uint64 `json:"nonce"` + Balance quantity.Quantity `json:"balance"` + Nonce uint64 `json:"nonce"` + TransfersNotBefore epochtime.EpochTime `json:"transfers_not_before,omitempty"` } // EscrowAccount is an escrow account the balance of which is subject to From b50c11da76e17a562d7c6803082d31cd1ff5f565 Mon Sep 17 00:00:00 2001 From: Warren He Date: Thu, 13 Feb 2020 16:08:31 -0800 Subject: [PATCH 2/2] add changelog --- .changelog/2672.breaking.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .changelog/2672.breaking.md diff --git a/.changelog/2672.breaking.md b/.changelog/2672.breaking.md new file mode 100644 index 00000000000..24c2debe5ae --- /dev/null +++ b/.changelog/2672.breaking.md @@ -0,0 +1,6 @@ +go staking: Add per-account lockup + +With this, we'll be able to set up special accounts in the genesis +document where they're not permitted to transfer staking tokens until +a the specified epoch time. +They can still delegate during that time.