Skip to content

Commit

Permalink
WIP: Add flag-protected support for SEP23 in txnbuild
Browse files Browse the repository at this point in the history
  • Loading branch information
2opremio committed Apr 14, 2021
1 parent a0bf286 commit 27a79c6
Show file tree
Hide file tree
Showing 3 changed files with 156 additions and 35 deletions.
60 changes: 53 additions & 7 deletions txnbuild/account_merge.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,18 @@ type AccountMerge struct {

// BuildXDR for AccountMerge returns a fully configured XDR Operation.
func (am *AccountMerge) BuildXDR() (xdr.Operation, error) {
var xdrOp xdr.MuxedAccount
return am.buildXDR(false)
}

err := xdrOp.SetAddress(am.Destination)
// BuildXDR for AccountMerge returns a fully configured XDR Operation.
func (am *AccountMerge) buildXDR(withSEP23 bool) (xdr.Operation, error) {
var xdrOp xdr.MuxedAccount
var err error
if withSEP23 {
err = xdrOp.SetAddressWithSEP23(am.Destination)
} else {
err = xdrOp.SetAddress(am.Destination)
}
if err != nil {
return xdr.Operation{}, errors.Wrap(err, "failed to set destination address")
}
Expand All @@ -27,7 +36,11 @@ func (am *AccountMerge) BuildXDR() (xdr.Operation, error) {
return xdr.Operation{}, errors.Wrap(err, "failed to build XDR OperationBody")
}
op := xdr.Operation{Body: body}
SetOpSourceAccount(&op, am.SourceAccount)
if withSEP23 {
SetOpSourceAccountWithSEP23(&op, am.SourceAccount)
} else {
SetOpSourceAccount(&op, am.SourceAccount)
}
return op, nil
}

Expand All @@ -37,10 +50,22 @@ func (am *AccountMerge) FromXDR(xdrOp xdr.Operation) error {
return errors.New("error parsing account_merge operation from xdr")
}

am.SourceAccount = accountFromXDR(xdrOp.SourceAccount)
return am.fromXDR(xdrOp, false)
}

func (am *AccountMerge) fromXDR(xdrOp xdr.Operation, withSEP23 bool) error {
if xdrOp.Body.Type != xdr.OperationTypeAccountMerge {
return errors.New("error parsing account_merge operation from xdr")
}

am.SourceAccount = accountFromXDR(xdrOp.SourceAccount, withSEP23)
if xdrOp.Body.Destination != nil {
aid := xdrOp.Body.Destination.ToAccountId()
am.Destination = aid.Address()
if withSEP23 {
am.Destination = xdrOp.Body.Destination.SEP23Address()
} else {
aid := xdrOp.Body.Destination.ToAccountId()
am.Destination = aid.Address()
}
}

return nil
Expand All @@ -49,7 +74,16 @@ func (am *AccountMerge) FromXDR(xdrOp xdr.Operation) error {
// Validate for AccountMerge validates the required struct fields. It returns an error if any of the fields are
// invalid. Otherwise, it returns nil.
func (am *AccountMerge) Validate() error {
_, err := xdr.AddressToAccountId(am.Destination)
return am.validate(false)
}

func (am *AccountMerge) validate(withSEP23 bool) error {
var err error
if withSEP23 {
_, err = xdr.AddressToAccountId(am.Destination)
} else {
_, err = xdr.SEP23AddressToMuxedAccount(am.Destination)
}
if err != nil {
return NewValidationError("Destination", err.Error())
}
Expand All @@ -61,3 +95,15 @@ func (am *AccountMerge) Validate() error {
func (am *AccountMerge) GetSourceAccount() string {
return am.SourceAccount
}

func (am *AccountMerge) BuildXDRWithSEP23() (xdr.Operation, error) {
return am.buildXDR(true)
}

func (am *AccountMerge) FromXDRWithSEP23(xdrOp xdr.Operation) error {
return am.fromXDR(xdrOp, true)
}

func (am *AccountMerge) ValidateWithSEP23() error {
return am.validate(true)
}
33 changes: 27 additions & 6 deletions txnbuild/operation.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ type Operation interface {
FromXDR(xdrOp xdr.Operation) error
Validate() error
GetSourceAccount() string
BuildXDRWithSEP23() (xdr.Operation, error)
FromXDRWithSEP23(xdrOp xdr.Operation) error
ValidateWithSEP23() error
}

// SetOpSourceAccount sets the source account ID on an Operation.
Expand All @@ -24,8 +27,18 @@ func SetOpSourceAccount(op *xdr.Operation, sourceAccount string) {
op.SourceAccount = &opSourceAccountID
}

// SetOpSourceAccount sets the source account ID on an Operation, allowing M-strkeys (as defined in SEP23).
func SetOpSourceAccountWithSEP23(op *xdr.Operation, sourceAccount string) {
if sourceAccount == "" {
return
}
var opSourceAccountID xdr.MuxedAccount
opSourceAccountID.SetAddressWithSEP23(sourceAccount)
op.SourceAccount = &opSourceAccountID
}

// operationFromXDR returns a txnbuild Operation from its corresponding XDR operation
func operationFromXDR(xdrOp xdr.Operation) (Operation, error) {
func operationFromXDR(xdrOp xdr.Operation, withSEP23 bool) (Operation, error) {
var newOp Operation
switch xdrOp.Body.Type {
case xdr.OperationTypeCreateAccount:
Expand Down Expand Up @@ -75,15 +88,23 @@ func operationFromXDR(xdrOp xdr.Operation) (Operation, error) {
default:
return nil, fmt.Errorf("unknown operation type: %d", xdrOp.Body.Type)
}

err := newOp.FromXDR(xdrOp)
var err error
if withSEP23 {
err = newOp.FromXDRWithSEP23(xdrOp)
} else {
err = newOp.FromXDR(xdrOp)
}
return newOp, err
}

func accountFromXDR(account *xdr.MuxedAccount) string {
func accountFromXDR(account *xdr.MuxedAccount, withSEP23 bool) string {
if account != nil {
aid := account.ToAccountId()
return aid.Address()
if withSEP23 {
return account.SEP23Address()
} else {
aid := account.ToAccountId()
return aid.Address()
}
}
return ""
}
98 changes: 76 additions & 22 deletions txnbuild/transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -514,18 +514,33 @@ func (t GenericTransaction) FeeBump() (*FeeBumpTransaction, bool) {
return t.feeBump, t.feeBump != nil
}

type TransactionOption int

const (
TransactionEnableSEP23 = iota
)

func isSEP23Enabled(options []TransactionOption) bool {
for _, opt := range options {
if opt == TransactionEnableSEP23 {
return true
}
}
return false
}

// TransactionFromXDR parses the supplied transaction envelope in base64 XDR
// and returns a GenericTransaction instance.
func TransactionFromXDR(txeB64 string) (*GenericTransaction, error) {
func TransactionFromXDR(txeB64 string, options ...TransactionOption) (*GenericTransaction, error) {
var xdrEnv xdr.TransactionEnvelope
err := xdr.SafeUnmarshalBase64(txeB64, &xdrEnv)
if err != nil {
return nil, errors.Wrap(err, "unable to unmarshal transaction envelope")
}
return transactionFromParsedXDR(xdrEnv)
return transactionFromParsedXDR(xdrEnv, isSEP23Enabled(options))
}

func transactionFromParsedXDR(xdrEnv xdr.TransactionEnvelope) (*GenericTransaction, error) {
func transactionFromParsedXDR(xdrEnv xdr.TransactionEnvelope, withSEP23 bool) (*GenericTransaction, error) {
var err error
newTx := &GenericTransaction{}

Expand All @@ -534,11 +549,19 @@ func transactionFromParsedXDR(xdrEnv xdr.TransactionEnvelope) (*GenericTransacti
innerTx, err = transactionFromParsedXDR(xdr.TransactionEnvelope{
Type: xdr.EnvelopeTypeEnvelopeTypeTx,
V1: xdrEnv.FeeBump.Tx.InnerTx.V1,
})
}, withSEP23)
if err != nil {
return newTx, errors.New("could not parse inner transaction")
}
feeBumpAccount := xdrEnv.FeeBumpAccount().ToAccountId()
var feeAccount string
if withSEP23 {
feeBumpAccount := xdrEnv.FeeBumpAccount()
feeAccount = feeBumpAccount.SEP23Address()
} else {
feeBumpAccount := xdrEnv.FeeBumpAccount().ToAccountId()
feeAccount = feeBumpAccount.Address()
}

newTx.feeBump = &FeeBumpTransaction{
envelope: xdrEnv,
// A fee-bump transaction has an effective number of operations equal to one plus the
Expand All @@ -548,12 +571,19 @@ func transactionFromParsedXDR(xdrEnv xdr.TransactionEnvelope) (*GenericTransacti
baseFee: xdrEnv.FeeBumpFee() / int64(len(innerTx.simple.operations)+1),
maxFee: xdrEnv.FeeBumpFee(),
inner: innerTx.simple,
feeAccount: feeBumpAccount.Address(),
feeAccount: feeAccount,
}

return newTx, nil
}

sourceAccount := xdrEnv.SourceAccount().ToAccountId()
var accountID string
if withSEP23 {
sourceAccount := xdrEnv.SourceAccount()
accountID = sourceAccount.SEP23Address()
} else {
sourceAccount := xdrEnv.SourceAccount().ToAccountId()
accountID = sourceAccount.Address()
}

totalFee := int64(xdrEnv.Fee())
baseFee := totalFee
Expand All @@ -566,7 +596,7 @@ func transactionFromParsedXDR(xdrEnv xdr.TransactionEnvelope) (*GenericTransacti
baseFee: baseFee,
maxFee: totalFee,
sourceAccount: SimpleAccount{
AccountID: sourceAccount.Address(),
AccountID: accountID,
Sequence: xdrEnv.SeqNum(),
},
operations: nil,
Expand All @@ -585,7 +615,7 @@ func transactionFromParsedXDR(xdrEnv xdr.TransactionEnvelope) (*GenericTransacti

operations := xdrEnv.Operations()
for _, op := range operations {
newOp, err := operationFromXDR(op)
newOp, err := operationFromXDR(op, withSEP23)
if err != nil {
return nil, err
}
Expand All @@ -604,6 +634,7 @@ type TransactionParams struct {
BaseFee int64
Memo Memo
Timebounds Timebounds
Options []TransactionOption
}

// NewTransaction returns a new Transaction instance
Expand Down Expand Up @@ -634,10 +665,18 @@ func NewTransaction(params TransactionParams) (*Transaction, error) {
memo: params.Memo,
timebounds: params.Timebounds,
}

accountID, err := xdr.AddressToAccountId(tx.sourceAccount.AccountID)
if err != nil {
return nil, errors.Wrap(err, "account id is not valid")
withSEP23 := isSEP23Enabled(params.Options)
var sourceAccount xdr.MuxedAccount
if withSEP23 {
if err := sourceAccount.SetAddressWithSEP23(tx.sourceAccount.AccountID); err != nil {
return nil, errors.Wrap(err, "account id is not valid")
}
} else {
accountID, err := xdr.AddressToAccountId(tx.sourceAccount.AccountID)
if err != nil {
return nil, errors.Wrap(err, "account id is not valid")
}
sourceAccount = accountID.ToMuxedAccount()
}

if tx.baseFee < MinBaseFee {
Expand Down Expand Up @@ -669,7 +708,7 @@ func NewTransaction(params TransactionParams) (*Transaction, error) {
Type: xdr.EnvelopeTypeEnvelopeTypeTx,
V1: &xdr.TransactionV1Envelope{
Tx: xdr.Transaction{
SourceAccount: accountID.ToMuxedAccount(),
SourceAccount: sourceAccount,
Fee: xdr.Uint32(tx.maxFee),
SeqNum: xdr.SequenceNumber(sequence),
TimeBounds: &xdr.TimeBounds{
Expand All @@ -694,8 +733,15 @@ func NewTransaction(params TransactionParams) (*Transaction, error) {
if verr := op.Validate(); verr != nil {
return nil, errors.Wrap(verr, fmt.Sprintf("validation failed for %T operation", op))
}

xdrOperation, err2 := op.BuildXDR()
var (
err2 error
xdrOperation xdr.Operation
)
if withSEP23 {
xdrOperation, err2 = op.BuildXDRWithSEP23()
} else {
xdrOperation, err2 = op.BuildXDR()
}
if err2 != nil {
return nil, errors.Wrap(err2, fmt.Sprintf("failed to build operation %T", op))
}
Expand All @@ -712,6 +758,7 @@ type FeeBumpTransactionParams struct {
Inner *Transaction
FeeAccount string
BaseFee int64
Options []TransactionOption
}

func convertToV1(tx *Transaction) (*Transaction, error) {
Expand Down Expand Up @@ -782,16 +829,23 @@ func NewFeeBumpTransaction(params FeeBumpTransactionParams) (*FeeBumpTransaction
)
}

accountID, err := xdr.AddressToAccountId(tx.feeAccount)
if err != nil {
return tx, errors.Wrap(err, "fee account is not a valid address")
var feeSource xdr.MuxedAccount
if isSEP23Enabled(params.Options) {
if err := feeSource.SetAddressWithSEP23(tx.feeAccount); err != nil {
return tx, errors.Wrap(err, "fee account is not a valid address")
}
} else {
accountID, err := xdr.AddressToAccountId(tx.feeAccount)
if err != nil {
return tx, errors.Wrap(err, "fee account is not a valid address")
}
feeSource = accountID.ToMuxedAccount()
}

tx.envelope = xdr.TransactionEnvelope{
Type: xdr.EnvelopeTypeEnvelopeTypeTxFeeBump,
FeeBump: &xdr.FeeBumpTransactionEnvelope{
Tx: xdr.FeeBumpTransaction{
FeeSource: accountID.ToMuxedAccount(),
FeeSource: feeSource,
Fee: xdr.Int64(tx.maxFee),
InnerTx: xdr.FeeBumpTransactionInnerTx{
Type: xdr.EnvelopeTypeEnvelopeTypeTx,
Expand Down

0 comments on commit 27a79c6

Please sign in to comment.