Skip to content

Commit

Permalink
runtime-sdk: Add support for consensus staking
Browse files Browse the repository at this point in the history
  • Loading branch information
kostko committed Sep 19, 2022
1 parent ae0f737 commit 722549d
Show file tree
Hide file tree
Showing 18 changed files with 2,107 additions and 212 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

39 changes: 28 additions & 11 deletions cli/cmd/accounts.go
Original file line number Diff line number Diff line change
Expand Up @@ -598,7 +598,7 @@ var (

acc := common.LoadAccount(cfg, npa.AccountName)

var sigTx interface{}
var sigTx, meta interface{}
switch npa.ParaTime {
case nil:
// Consensus layer delegation.
Expand All @@ -615,10 +615,22 @@ var (
cobra.CheckErr(err)
default:
// ParaTime delegation.
cobra.CheckErr("delegations within paratimes are not supported; use --no-paratime")
// TODO: This should actually query the ParaTime (or config) to check what the consensus
// layer denomination is in the ParaTime. Assume NATIVE for now.
amountBaseUnits, err := helpers.ParseParaTimeDenomination(npa.ParaTime, amount, types.NativeDenomination)
cobra.CheckErr(err)

// Prepare transaction.
tx := consensusaccounts.NewDelegateTx(nil, &consensusaccounts.Delegate{
To: *toAddr,
Amount: *amountBaseUnits,
})

sigTx, meta, err = common.SignParaTimeTransaction(ctx, npa, acc, conn, tx)
cobra.CheckErr(err)
}

common.BroadcastTransaction(ctx, npa.ParaTime, conn, sigTx, nil, nil)
common.BroadcastTransaction(ctx, npa.ParaTime, conn, sigTx, meta, nil)
},
}

Expand Down Expand Up @@ -651,15 +663,14 @@ var (

acc := common.LoadAccount(cfg, npa.AccountName)

var sigTx interface{}
var shares quantity.Quantity
err = shares.UnmarshalText([]byte(amount))
cobra.CheckErr(err)

var sigTx, meta interface{}
switch npa.ParaTime {
case nil:
// Consensus layer delegation.
var shares quantity.Quantity
err = shares.UnmarshalText([]byte(amount))
cobra.CheckErr(err)

// Prepare transaction.
tx := staking.NewReclaimEscrowTx(0, nil, &staking.ReclaimEscrow{
Account: fromAddr.ConsensusAddress(),
Shares: shares,
Expand All @@ -669,10 +680,16 @@ var (
cobra.CheckErr(err)
default:
// ParaTime delegation.
cobra.CheckErr("delegations within paratimes are not supported; use --no-paratime")
tx := consensusaccounts.NewUndelegateTx(nil, &consensusaccounts.Undelegate{
From: *fromAddr,
Shares: shares,
})

sigTx, meta, err = common.SignParaTimeTransaction(ctx, npa, acc, conn, tx)
cobra.CheckErr(err)
}

common.BroadcastTransaction(ctx, npa.ParaTime, conn, sigTx, nil, nil)
common.BroadcastTransaction(ctx, npa.ParaTime, conn, sigTx, meta, nil)
},
}

Expand Down
100 changes: 95 additions & 5 deletions client-sdk/go/modules/consensusaccounts/consensus_accounts.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,17 @@ import (

const (
// Callable methods.
methodDeposit = "consensus.Deposit"
methodWithdraw = "consensus.Withdraw"
methodDeposit = "consensus.Deposit"
methodWithdraw = "consensus.Withdraw"
methodDelegate = "consensus.Delegate"
methodUndelegate = "consensus.Undelegate"

// Queries.
methodParameters = "consensus_accounts.Parameters"
methodBalance = "consensus.Balance"
methodAccount = "consensus.Account"
methodParameters = "consensus_accounts.Parameters"
methodBalance = "consensus.Balance"
methodAccount = "consensus.Account"
methodDelegation = "consensus.Delegation"
methodDelegations = "consensus.Delegations"
)

// V1 is the v1 consensus accounts module interface.
Expand All @@ -32,6 +36,12 @@ type V1 interface {
// Withdraw generates a consensus.Withdraw transaction.
Withdraw(to *types.Address, amount types.BaseUnits) *client.TransactionBuilder

// Delegate generates a consensus.Delegate transaction.
Delegate(to types.Address, amount types.BaseUnits) *client.TransactionBuilder

// Undelegate generates a consensus.Undelegate transaction.
Undelegate(from types.Address, shares types.Quantity) *client.TransactionBuilder

// Parameters queries the consensus accounts module parameters.
Parameters(ctx context.Context, round uint64) (*Parameters, error)

Expand All @@ -41,6 +51,12 @@ type V1 interface {
// ConsensusAccount queries the given consensus layer account.
ConsensusAccount(ctx context.Context, round uint64, query *AccountQuery) (*staking.Account, error)

// Delegation queries the given delegation metadata based on a (from, to) address pair.
Delegation(ctx context.Context, round uint64, query *DelegationQuery) (*DelegationInfo, error)

// Delegations queries all delegation metadata originating from a given account.
Delegations(ctx context.Context, round uint64, query *DelegationsQuery) ([]*ExtendedDelegationInfo, error)

// GetEvents returns all consensus accounts events emitted in a given block.
GetEvents(ctx context.Context, round uint64) ([]*Event, error)
}
Expand All @@ -65,6 +81,22 @@ func (a *v1) Withdraw(to *types.Address, amount types.BaseUnits) *client.Transac
})
}

// Implements V1.
func (a *v1) Delegate(to types.Address, amount types.BaseUnits) *client.TransactionBuilder {
return client.NewTransactionBuilder(a.rc, methodDelegate, &Delegate{
To: to,
Amount: amount,
})
}

// Implements V1.
func (a *v1) Undelegate(from types.Address, shares types.Quantity) *client.TransactionBuilder {
return client.NewTransactionBuilder(a.rc, methodUndelegate, &Undelegate{
From: from,
Shares: shares,
})
}

// Implements V1.
func (a *v1) Parameters(ctx context.Context, round uint64) (*Parameters, error) {
var params Parameters
Expand Down Expand Up @@ -95,6 +127,26 @@ func (a *v1) ConsensusAccount(ctx context.Context, round uint64, query *AccountQ
return &account, nil
}

// Implements V1.
func (a *v1) Delegation(ctx context.Context, round uint64, query *DelegationQuery) (*DelegationInfo, error) {
var di DelegationInfo
err := a.rc.Query(ctx, round, methodDelegation, query, &di)
if err != nil {
return nil, err
}
return &di, nil
}

// Implements V1.
func (a *v1) Delegations(ctx context.Context, round uint64, query *DelegationsQuery) ([]*ExtendedDelegationInfo, error) {
var dis []*ExtendedDelegationInfo
err := a.rc.Query(ctx, round, methodDelegations, query, &dis)
if err != nil {
return nil, err
}
return dis, nil
}

// Implements V1.
func (a *v1) GetEvents(ctx context.Context, round uint64) ([]*Event, error) {
rawEvs, err := a.rc.GetEventsRaw(ctx, round)
Expand Down Expand Up @@ -146,6 +198,30 @@ func DecodeEvent(event *types.Event) ([]client.DecodedEvent, error) {
for _, ev := range evs {
events = append(events, &Event{Withdraw: ev})
}
case DelegateEventCode:
var evs []*DelegateEvent
if err := cbor.Unmarshal(event.Value, &evs); err != nil {
return nil, fmt.Errorf("decode consensus accounts delegate event value: %w", err)
}
for _, ev := range evs {
events = append(events, &Event{Delegate: ev})
}
case UndelegateStartEventCode:
var evs []*UndelegateStartEvent
if err := cbor.Unmarshal(event.Value, &evs); err != nil {
return nil, fmt.Errorf("decode consensus accounts undelegate start event value: %w", err)
}
for _, ev := range evs {
events = append(events, &Event{UndelegateStart: ev})
}
case UndelegateDoneEventCode:
var evs []*UndelegateDoneEvent
if err := cbor.Unmarshal(event.Value, &evs); err != nil {
return nil, fmt.Errorf("decode consensus accounts undelegate done event value: %w", err)
}
for _, ev := range evs {
events = append(events, &Event{UndelegateDone: ev})
}
default:
return nil, fmt.Errorf("invalid consensus accounts event code: %v", event.Code)
}
Expand All @@ -170,3 +246,17 @@ func NewWithdrawTx(fee *types.Fee, body *Withdraw) *types.Transaction {
tx.AuthInfo.Fee.ConsensusMessages = 1
return tx
}

// NewDelegateTx generates a new consensus.Delegate transaction.
func NewDelegateTx(fee *types.Fee, body *Delegate) *types.Transaction {
tx := types.NewTransaction(fee, methodDelegate, body)
tx.AuthInfo.Fee.ConsensusMessages = 1
return tx
}

// NewUndelegateTx generates a new consensus.Undelegate transaction.
func NewUndelegateTx(fee *types.Fee, body *Undelegate) *types.Transaction {
tx := types.NewTransaction(fee, methodUndelegate, body)
tx.AuthInfo.Fee.ConsensusMessages = 1
return tx
}
101 changes: 96 additions & 5 deletions client-sdk/go/modules/consensusaccounts/types.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package consensusaccounts

import "github.com/oasisprotocol/oasis-sdk/client-sdk/go/types"
import (
beacon "github.com/oasisprotocol/oasis-core/go/beacon/api"

"github.com/oasisprotocol/oasis-sdk/client-sdk/go/types"
)

// Deposit are the arguments for consensus.Deposit method.
type Deposit struct {
Expand All @@ -14,6 +18,18 @@ type Withdraw struct {
Amount types.BaseUnits `json:"amount"`
}

// Delegate are the arguments for consensus.Delegate method.
type Delegate struct {
To types.Address `json:"to"`
Amount types.BaseUnits `json:"amount"`
}

// Undelegate are the arguments for consensus.Undelegate method.
type Undelegate struct {
From types.Address `json:"from"`
Shares types.Quantity `json:"shares"`
}

// BalanceQuery are the arguments for consensus.Balance method.
type BalanceQuery struct {
Address types.Address `json:"address"`
Expand All @@ -29,15 +45,44 @@ type AccountQuery struct {
Address types.Address `json:"address"`
}

// DelegationQuery are the arguments for consensus.Delegation method.
type DelegationQuery struct {
From types.Address `json:"from"`
To types.Address `json:"to"`
}

// DelegationsQuery are the arguments for consensus.Delegations method.
type DelegationsQuery struct {
From types.Address `json:"from"`
}

// DelegationInfo is information about a delegation.
type DelegationInfo struct {
Shares types.Quantity `json:"shares"`
}

// ExtendedDelegationInfo is extended information about a delegation.
type ExtendedDelegationInfo struct {
To types.Address `json:"to"`
Shares types.Quantity `json:"shares"`
}

// GasCosts are the consensus accounts module gas costs.
type GasCosts struct {
TxDeposit uint64 `json:"tx_deposit"`
TxWithdraw uint64 `json:"tx_withdraw"`
TxDeposit uint64 `json:"tx_deposit"`
TxWithdraw uint64 `json:"tx_withdraw"`
TxDelegate uint64 `json:"tx_delegate"`
TxUndelegate uint64 `json:"tx_undelegate"`
}

// Parameters are the parameters for the consensus accounts module.
type Parameters struct {
GasCosts GasCosts `json:"gas_costs"`

DisableDelegate bool `json:"disable_delegate"`
DisableUndelegate bool `json:"disable_undelegate"`
DisableDeposit bool `json:"disable_deposit"`
DisableWithdraw bool `json:"disable_withdraw"`
}

// ConsensusError contains error details from the consensus layer.
Expand All @@ -54,6 +99,12 @@ const (
DepositEventCode = 1
// WithdrawEventCode is the event code for the withdraw event.
WithdrawEventCode = 2
// DelegateEventCode is the event code for the delegate event.
DelegateEventCode = 3
// UndelegateStartEventCode is the event code for the undelegate start event.
UndelegateStartEventCode = 4
// UndelegateDoneEventCode is the event code for the undelegate done event.
UndelegateDoneEventCode = 5
)

// DepositEvent is a deposit event.
Expand Down Expand Up @@ -84,8 +135,48 @@ func (we *WithdrawEvent) IsSuccess() bool {
return we.Error == nil
}

// DelegateEvent is a delegate event.
type DelegateEvent struct {
From types.Address `json:"from"`
Nonce uint64 `json:"nonce"`
To types.Address `json:"to"`
Amount types.BaseUnits `json:"amount"`
Error *ConsensusError `json:"error,omitempty"`
}

// IsSuccess checks whether the event indicates a successful operation.
func (we *DelegateEvent) IsSuccess() bool {
return we.Error == nil
}

// UndelegateStartEvent is an undelegate start event.
type UndelegateStartEvent struct {
From types.Address `json:"from"`
Nonce uint64 `json:"nonce"`
To types.Address `json:"to"`
Shares types.Quantity `json:"shares"`
DebondEndTime beacon.EpochTime `json:"debond_end_time"`
Error *ConsensusError `json:"error,omitempty"`
}

// IsSuccess checks whether the event indicates a successful operation.
func (we *UndelegateStartEvent) IsSuccess() bool {
return we.Error == nil
}

// UndelegateDoneEvent is an undelegate done event.
type UndelegateDoneEvent struct {
From types.Address `json:"from"`
To types.Address `json:"to"`
Shares types.Quantity `json:"shares"`
Amount types.BaseUnits `json:"amount"`
}

// Event is a consensus account event.
type Event struct {
Deposit *DepositEvent
Withdraw *WithdrawEvent
Deposit *DepositEvent
Withdraw *WithdrawEvent
Delegate *DelegateEvent
UndelegateStart *UndelegateStartEvent
UndelegateDone *UndelegateDoneEvent
}
1 change: 1 addition & 0 deletions contract-sdk/specs/access/oas173/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions contract-sdk/specs/token/oas20/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 722549d

Please sign in to comment.