[rosetta] implement balance tracking and redo tx construction (#8729)

Co-authored-by: Alessio Treglia <alessio@tendermint.com>
Co-authored-by: Robert Zaremba <robert@zaremba.ch>
This commit is contained in:
Frojdi Dymylja
2021-03-11 15:01:29 +00:00
committed by GitHub
co-authored by Alessio Treglia Robert Zaremba
parent 280ee4f15e
commit 288f8dda4b
23 changed files with 1637 additions and 1453 deletions
-84
View File
@@ -1,13 +1,6 @@
package types
import (
"fmt"
"strconv"
"strings"
"github.com/coinbase/rosetta-sdk-go/types"
"github.com/gogo/protobuf/proto"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
)
@@ -69,83 +62,6 @@ func (msg MsgSend) GetSigners() []sdk.AccAddress {
return []sdk.AccAddress{from}
}
// Rosetta interface
func (msg *MsgSend) ToOperations(withStatus bool, hasError bool) []*types.Operation {
var operations []*types.Operation
fromAddress := msg.FromAddress
toAddress := msg.ToAddress
amounts := msg.Amount
if len(amounts) == 0 {
return []*types.Operation{}
}
coin := amounts[0]
sendOp := func(account, amount string, index int) *types.Operation {
var status string
if withStatus {
status = "Success"
if hasError {
status = "Reverted"
}
}
return &types.Operation{
OperationIdentifier: &types.OperationIdentifier{
Index: int64(index),
},
Type: proto.MessageName(msg),
Status: status,
Account: &types.AccountIdentifier{
Address: account,
},
Amount: &types.Amount{
Value: amount,
Currency: &types.Currency{
Symbol: coin.Denom,
},
},
}
}
operations = append(operations,
sendOp(fromAddress, "-"+coin.Amount.String(), 0),
sendOp(toAddress, coin.Amount.String(), 1),
)
return operations
}
func (msg MsgSend) FromOperations(ops []*types.Operation) (sdk.Msg, error) {
var (
from, to sdk.AccAddress
sendAmt sdk.Coin
err error
)
for _, op := range ops {
if strings.HasPrefix(op.Amount.Value, "-") {
from, err = sdk.AccAddressFromBech32(op.Account.Address)
if err != nil {
return nil, err
}
continue
}
to, err = sdk.AccAddressFromBech32(op.Account.Address)
if err != nil {
return nil, err
}
amount, err := strconv.ParseInt(op.Amount.Value, 10, 64)
if err != nil {
return nil, fmt.Errorf("invalid amount")
}
sendAmt = sdk.NewCoin(op.Amount.Currency.Symbol, sdk.NewInt(amount))
}
return NewMsgSend(from, to, sdk.NewCoins(sendAmt)), nil
}
var _ sdk.Msg = &MsgMultiSend{}
// NewMsgMultiSend - construct arbitrary multi-in, multi-out send msg.
-50
View File
@@ -2,12 +2,6 @@
package types
import (
"fmt"
rosettatypes "github.com/coinbase/rosetta-sdk-go/types"
"github.com/gogo/protobuf/proto"
"github.com/cosmos/cosmos-sdk/server/rosetta"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
)
@@ -96,50 +90,6 @@ func (msg MsgWithdrawDelegatorReward) ValidateBasic() error {
return nil
}
func (msg *MsgWithdrawDelegatorReward) ToOperations(withStatus, hasError bool) []*rosettatypes.Operation {
var status string
if withStatus {
status = rosetta.StatusSuccess
if hasError {
status = rosetta.StatusReverted
}
}
op := &rosettatypes.Operation{
OperationIdentifier: &rosettatypes.OperationIdentifier{
Index: 0,
},
RelatedOperations: nil,
Type: proto.MessageName(msg),
Status: status,
Account: &rosettatypes.AccountIdentifier{
Address: msg.DelegatorAddress,
SubAccount: &rosettatypes.SubAccountIdentifier{
Address: msg.ValidatorAddress,
},
},
}
return []*rosettatypes.Operation{op}
}
func (msg *MsgWithdrawDelegatorReward) FromOperations(ops []*rosettatypes.Operation) (sdk.Msg, error) {
if len(ops) != 1 {
return nil, fmt.Errorf("expected one operation")
}
op := ops[0]
if op.Account == nil {
return nil, fmt.Errorf("account identifier must be specified")
}
if op.Account.SubAccount == nil {
return nil, fmt.Errorf("account identifier subaccount must be specified")
}
return &MsgWithdrawDelegatorReward{
DelegatorAddress: op.Account.Address,
ValidatorAddress: op.Account.SubAccount.Address,
}, nil
}
func NewMsgWithdrawValidatorCommission(valAddr sdk.ValAddress) *MsgWithdrawValidatorCommission {
return &MsgWithdrawValidatorCommission{
ValidatorAddress: valAddr.String(),
-274
View File
@@ -2,17 +2,9 @@ package types
import (
"bytes"
"fmt"
"strconv"
"strings"
"github.com/gogo/protobuf/proto"
rosettatypes "github.com/coinbase/rosetta-sdk-go/types"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
"github.com/cosmos/cosmos-sdk/server/rosetta"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
)
@@ -264,90 +256,6 @@ func (msg MsgDelegate) ValidateBasic() error {
return nil
}
// Rosetta Msg interface.
func (msg *MsgDelegate) ToOperations(withStatus bool, hasError bool) []*rosettatypes.Operation {
var operations []*rosettatypes.Operation
delAddr := msg.DelegatorAddress
valAddr := msg.ValidatorAddress
coin := msg.Amount
delOp := func(account *rosettatypes.AccountIdentifier, amount string, index int) *rosettatypes.Operation {
var status string
if withStatus {
status = rosetta.StatusSuccess
if hasError {
status = rosetta.StatusReverted
}
}
return &rosettatypes.Operation{
OperationIdentifier: &rosettatypes.OperationIdentifier{
Index: int64(index),
},
Type: proto.MessageName(msg),
Status: status,
Account: account,
Amount: &rosettatypes.Amount{
Value: amount,
Currency: &rosettatypes.Currency{
Symbol: coin.Denom,
},
},
}
}
delAcc := &rosettatypes.AccountIdentifier{
Address: delAddr,
}
valAcc := &rosettatypes.AccountIdentifier{
Address: "staking_account",
SubAccount: &rosettatypes.SubAccountIdentifier{
Address: valAddr,
},
}
operations = append(operations,
delOp(delAcc, "-"+coin.Amount.String(), 0),
delOp(valAcc, coin.Amount.String(), 1),
)
return operations
}
func (msg *MsgDelegate) FromOperations(ops []*rosettatypes.Operation) (sdk.Msg, error) {
var (
delAddr sdk.AccAddress
valAddr sdk.ValAddress
sendAmt sdk.Coin
err error
)
for _, op := range ops {
if strings.HasPrefix(op.Amount.Value, "-") {
if op.Account == nil {
return nil, fmt.Errorf("account identifier must be specified")
}
delAddr, err = sdk.AccAddressFromBech32(op.Account.Address)
if err != nil {
return nil, err
}
continue
}
if op.Account.SubAccount == nil {
return nil, fmt.Errorf("account identifier subaccount must be specified")
}
valAddr, err = sdk.ValAddressFromBech32(op.Account.SubAccount.Address)
if err != nil {
return nil, err
}
amount, err := strconv.ParseInt(op.Amount.Value, 10, 64)
if err != nil {
return nil, fmt.Errorf("invalid amount: %w", err)
}
sendAmt = sdk.NewCoin(op.Amount.Currency.Symbol, sdk.NewInt(amount))
}
return NewMsgDelegate(delAddr, valAddr, sendAmt), nil
}
// NewMsgBeginRedelegate creates a new MsgBeginRedelegate instance.
//nolint:interfacer
func NewMsgBeginRedelegate(
@@ -403,103 +311,6 @@ func (msg MsgBeginRedelegate) ValidateBasic() error {
return nil
}
// Rosetta Msg interface.
func (msg *MsgBeginRedelegate) ToOperations(withStatus bool, hasError bool) []*rosettatypes.Operation {
var operations []*rosettatypes.Operation
delAddr := msg.DelegatorAddress
srcValAddr := msg.ValidatorSrcAddress
destValAddr := msg.ValidatorDstAddress
coin := msg.Amount
delOp := func(account *rosettatypes.AccountIdentifier, amount string, index int) *rosettatypes.Operation {
var status string
if withStatus {
status = rosetta.StatusSuccess
if hasError {
status = rosetta.StatusReverted
}
}
return &rosettatypes.Operation{
OperationIdentifier: &rosettatypes.OperationIdentifier{
Index: int64(index),
},
Type: proto.MessageName(msg),
Status: status,
Account: account,
Amount: &rosettatypes.Amount{
Value: amount,
Currency: &rosettatypes.Currency{
Symbol: coin.Denom,
},
},
}
}
srcValAcc := &rosettatypes.AccountIdentifier{
Address: delAddr,
SubAccount: &rosettatypes.SubAccountIdentifier{
Address: srcValAddr,
},
}
destValAcc := &rosettatypes.AccountIdentifier{
Address: "staking_account",
SubAccount: &rosettatypes.SubAccountIdentifier{
Address: destValAddr,
},
}
operations = append(operations,
delOp(srcValAcc, "-"+coin.Amount.String(), 0),
delOp(destValAcc, coin.Amount.String(), 1),
)
return operations
}
func (msg *MsgBeginRedelegate) FromOperations(ops []*rosettatypes.Operation) (sdk.Msg, error) {
var (
delAddr sdk.AccAddress
srcValAddr sdk.ValAddress
destValAddr sdk.ValAddress
sendAmt sdk.Coin
err error
)
for _, op := range ops {
if strings.HasPrefix(op.Amount.Value, "-") {
if op.Account == nil {
return nil, fmt.Errorf("account identifier must be specified")
}
delAddr, err = sdk.AccAddressFromBech32(op.Account.Address)
if err != nil {
return nil, err
}
if op.Account.SubAccount == nil {
return nil, fmt.Errorf("account identifier subaccount must be specified")
}
srcValAddr, err = sdk.ValAddressFromBech32(op.Account.SubAccount.Address)
if err != nil {
return nil, err
}
continue
}
if op.Account.SubAccount == nil {
return nil, fmt.Errorf("account identifier subaccount must be specified")
}
destValAddr, err = sdk.ValAddressFromBech32(op.Account.SubAccount.Address)
if err != nil {
return nil, err
}
amount, err := strconv.ParseInt(op.Amount.Value, 10, 64)
if err != nil {
return nil, fmt.Errorf("invalid amount: %w", err)
}
sendAmt = sdk.NewCoin(op.Amount.Currency.Symbol, sdk.NewInt(amount))
}
return NewMsgBeginRedelegate(delAddr, srcValAddr, destValAddr, sendAmt), nil
}
// NewMsgUndelegate creates a new MsgUndelegate instance.
//nolint:interfacer
func NewMsgUndelegate(delAddr sdk.AccAddress, valAddr sdk.ValAddress, amount sdk.Coin) *MsgUndelegate {
@@ -547,88 +358,3 @@ func (msg MsgUndelegate) ValidateBasic() error {
return nil
}
// Rosetta Msg interface.
func (msg *MsgUndelegate) ToOperations(withStatus bool, hasError bool) []*rosettatypes.Operation {
var operations []*rosettatypes.Operation
delAddr := msg.DelegatorAddress
valAddr := msg.ValidatorAddress
coin := msg.Amount
delOp := func(account *rosettatypes.AccountIdentifier, amount string, index int) *rosettatypes.Operation {
var status string
if withStatus {
status = rosetta.StatusSuccess
if hasError {
status = rosetta.StatusReverted
}
}
return &rosettatypes.Operation{
OperationIdentifier: &rosettatypes.OperationIdentifier{
Index: int64(index),
},
Type: proto.MessageName(msg),
Status: status,
Account: account,
Amount: &rosettatypes.Amount{
Value: amount,
Currency: &rosettatypes.Currency{
Symbol: coin.Denom,
},
},
}
}
delAcc := &rosettatypes.AccountIdentifier{
Address: delAddr,
}
valAcc := &rosettatypes.AccountIdentifier{
Address: "staking_account",
SubAccount: &rosettatypes.SubAccountIdentifier{
Address: valAddr,
},
}
operations = append(operations,
delOp(valAcc, "-"+coin.Amount.String(), 0),
delOp(delAcc, coin.Amount.String(), 1),
)
return operations
}
func (msg *MsgUndelegate) FromOperations(ops []*rosettatypes.Operation) (sdk.Msg, error) {
var (
delAddr sdk.AccAddress
valAddr sdk.ValAddress
undelAmt sdk.Coin
err error
)
for _, op := range ops {
if strings.HasPrefix(op.Amount.Value, "-") {
if op.Account.SubAccount == nil {
return nil, fmt.Errorf("account identifier subaccount must be specified")
}
valAddr, err = sdk.ValAddressFromBech32(op.Account.SubAccount.Address)
if err != nil {
return nil, err
}
continue
}
if op.Account == nil {
return nil, fmt.Errorf("account identifier must be specified")
}
delAddr, err = sdk.AccAddressFromBech32(op.Account.Address)
if err != nil {
return nil, err
}
amount, err := strconv.ParseInt(op.Amount.Value, 10, 64)
if err != nil {
return nil, fmt.Errorf("invalid amount")
}
undelAmt = sdk.NewCoin(op.Amount.Currency.Symbol, sdk.NewInt(amount))
}
return NewMsgUndelegate(delAddr, valAddr, undelAmt), nil
}