Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

services/horizon, contractevents: Update tests to support ScValue overhaul #4816

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 5 additions & 7 deletions support/contractevents/burn.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,19 +36,17 @@ func (event *BurnEvent) parse(topics xdr.ScVec, value xdr.ScVal) error {
return ErrNotBurnEvent
}

rawFrom := topics[1]
from := parseAddress(&rawFrom)
if from == nil {
from, ok := topics[1].GetAddress()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

btw, what source did you find for reference on topics emitted for SAC events? It's parsed here, just wanted to check that also, thanks!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if !ok {
return ErrNotBurnEvent
}

event.From = MustScAddressToString(from)

amount := parseAmount(&value)
if amount == nil {
amount, ok := value.GetI128()
if !ok {
return ErrNotBurnEvent
}
event.Amount = amount

event.Amount = *amount
return nil
}
8 changes: 1 addition & 7 deletions support/contractevents/event.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ var (
xdr.ScSymbol("burn"): EventTypeBurn,
}

// TODO: Finer-grained parsing errors
ErrNotStellarAssetContract = errors.New("event was not from a Stellar Asset Contract")
ErrEventUnsupported = errors.New("this type of Stellar Asset Contract event is unsupported")
ErrEventIntegrity = errors.New("contract ID doesn't match asset + passphrase")
Expand Down Expand Up @@ -99,12 +98,7 @@ func NewStellarAssetContractEvent(event *Event, networkPassphrase string) (Stell
// For all parsing errors, we just continue, since it's not a real error,
// just an event non-complaint with SAC events.
rawAsset := topics[len(topics)-1]
assetContainer, ok := rawAsset.GetObj()
if !ok || assetContainer == nil {
return evt, ErrNotStellarAssetContract
}

assetBytes, ok := assetContainer.GetBin()
assetBytes, ok := rawAsset.GetBytes()
if !ok || assetBytes == nil {
return evt, ErrNotStellarAssetContract
}
Expand Down
53 changes: 21 additions & 32 deletions support/contractevents/event_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package contractevents

import (
"crypto/rand"
"encoding/base64"
"math"
"math/big"
"testing"
Expand Down Expand Up @@ -34,11 +33,7 @@ func TestScValCreators(t *testing.T) {
assert.EqualValues(t, *val.Sym, "hello")

val = makeAmount(1234)
obj, ok := val.GetObj()
assert.True(t, ok)
assert.NotNil(t, obj)

amt, ok := obj.GetI128()
amt, ok := val.GetI128()
assert.True(t, ok)
assert.EqualValues(t, 0, amt.Hi)
assert.EqualValues(t, 1234, amt.Lo)
Expand All @@ -52,11 +47,7 @@ func TestScValCreators(t *testing.T) {
Add(amount, big.NewInt(1234+4)) // now it's 2^66 + 1234

val = makeBigAmount(amount)
obj, ok = val.GetObj()
assert.True(t, ok)
assert.NotNil(t, obj)

amt, ok = obj.GetI128()
amt, ok = val.GetI128()
assert.True(t, ok)
assert.EqualValues(t, 4, amt.Hi)
assert.EqualValues(t, 1234, amt.Lo)
Expand Down Expand Up @@ -136,9 +127,10 @@ func TestSACTransferEvent(t *testing.T) {
// Ensure that invalid asset binaries are rejected
t.Run("bad asset binary", func(t *testing.T) {
resetEvent()
bsAsset := make([]byte, 42)
rand.Read(bsAsset)
(*baseXdrEvent.Body.V0.Topics[3].Obj).Bin = &bsAsset
rawBsAsset := make([]byte, 42)
rand.Read(rawBsAsset)
bsAsset := xdr.ScBytes(rawBsAsset)
baseXdrEvent.Body.V0.Topics[3].Bytes = &bsAsset
_, err = NewStellarAssetContractEvent(&baseXdrEvent, passphrase)
require.Error(t, err)
})
Expand Down Expand Up @@ -244,19 +236,20 @@ func TestFuzzingSACEventParser(t *testing.T) {
}
}

func TestRealXdr(t *testing.T) {
base64xdr := "AAAAAAAAAAGP097PJPXCcbtgOhu8wDc/ELPABxTdosN//YtrzxEJyAAAAAEAAAAAAAAABAAAAAUAAAAIdHJhbnNmZXIAAAAEAAAAAQAAAAgAAAAAAAAAAHN2/eiOTNYcwPspSheGs/HQYfXy8cpXRl+qkyIRuUbWAAAABAAAAAEAAAAIAAAAAAAAAAB4Ijl70f/hhiVmJftmpmXIoHZyUoyEiPSrpZAd5RfalwAAAAQAAAABAAAABgAAACVVU0QAOnN2/eiOTNYcwPspSheGs/HQYfXy8cpXRl+qkyIRuUbWAAAAAAAABAAAAAEAAAAFAAAAABHhowAAAAAAAAAAAA=="
// FIXME: This needs to be updated with real XDR once that's possible.
// func TestRealXdr(t *testing.T) {
// base64xdr := "AAAAAAAAAAGP097PJPXCcbtgOhu8wDc/ELPABxTdosN//YtrzxEJyAAAAAEAAAAAAAAABAAAAAUAAAAIdHJhbnNmZXIAAAAEAAAAAQAAAAgAAAAAAAAAAHN2/eiOTNYcwPspSheGs/HQYfXy8cpXRl+qkyIRuUbWAAAABAAAAAEAAAAIAAAAAAAAAAB4Ijl70f/hhiVmJftmpmXIoHZyUoyEiPSrpZAd5RfalwAAAAQAAAABAAAABgAAACVVU0QAOnN2/eiOTNYcwPspSheGs/HQYfXy8cpXRl+qkyIRuUbWAAAAAAAABAAAAAEAAAAFAAAAABHhowAAAAAAAAAAAA=="

rawXdr, err := base64.StdEncoding.DecodeString(base64xdr)
require.NoError(t, err)
// rawXdr, err := base64.StdEncoding.DecodeString(base64xdr)
// require.NoError(t, err)

event := xdr.ContractEvent{}
require.NoError(t, event.UnmarshalBinary(rawXdr))
// event := xdr.ContractEvent{}
// require.NoError(t, event.UnmarshalBinary(rawXdr))

parsed, err := NewStellarAssetContractEvent(&event, "Standalone Network ; February 2017")
assert.NoError(t, err)
assert.Equal(t, EventTypeTransfer, parsed.GetType())
}
// parsed, err := NewStellarAssetContractEvent(&event, "Standalone Network ; February 2017")
// assert.NoError(t, err)
// assert.Equal(t, EventTypeTransfer, parsed.GetType())
// }

//
// Test suite helpers below
Expand Down Expand Up @@ -286,14 +279,10 @@ func makeTransferTopic(asset xdr.Asset) xdr.ScVec {
contractStr := strkey.MustEncode(strkey.VersionByteContract, zeroContractHash[:])

return xdr.ScVec([]xdr.ScVal{
// event name
makeSymbol("transfer"),
// from
makeAddress(randomAccount),
// to
makeAddress(contractStr),
// asset details
makeAsset(asset),
makeSymbol("transfer"), // event name
makeAddress(randomAccount), // from
makeAddress(contractStr), // to
makeAsset(asset), // asset details
})
}

Expand Down
28 changes: 7 additions & 21 deletions support/contractevents/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,26 +127,17 @@ func makeBigAmount(amount *big.Int) xdr.ScVal {
hi := new(big.Int).Rsh(amount, 64)
lo := amount.And(amount, keepLower)

amountObj := &xdr.ScObject{
Type: xdr.ScObjectTypeScoI128,
return xdr.ScVal{
Type: xdr.ScValTypeScvI128,
I128: &xdr.Int128Parts{
Lo: xdr.Uint64(lo.Uint64()),
Hi: xdr.Uint64(hi.Uint64()),
},
}

return xdr.ScVal{
Type: xdr.ScValTypeScvObject,
Obj: &amountObj,
}
}

func makeAddress(address string) xdr.ScVal {
scAddress := xdr.ScAddress{}
scObject := &xdr.ScObject{
Type: xdr.ScObjectTypeScoAddress,
Address: &scAddress,
}

switch address[0] {
case 'C':
Expand All @@ -163,8 +154,8 @@ func makeAddress(address string) xdr.ScVal {
}

return xdr.ScVal{
Type: xdr.ScValTypeScvObject,
Obj: &scObject,
Type: xdr.ScValTypeScvAddress,
Address: &scAddress,
}
}

Expand Down Expand Up @@ -212,14 +203,9 @@ func makeAsset(asset xdr.Asset) xdr.ScVal {
panic("unexpected asset type")
}

slice := buffer.Bytes()
scObject := &xdr.ScObject{
Type: xdr.ScObjectTypeScoBytes,
Bin: &slice,
}

slice := xdr.ScBytes(buffer.Bytes())
return xdr.ScVal{
Type: xdr.ScValTypeScvObject,
Obj: &scObject,
Type: xdr.ScValTypeScvBytes,
Bytes: &slice,
}
}
63 changes: 22 additions & 41 deletions support/contractevents/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,15 @@ var ErrNotBalanceChangeEvent = errors.New("event doesn't represent a balance cha
// MustScAddressToString converts the low-level `xdr.ScAddress` union into the
// appropriate strkey (contract C... or account ID G...), panicking on any
// error. If the address is a nil pointer, this returns the empty string.
func MustScAddressToString(address *xdr.ScAddress) string {
func MustScAddressToString(address xdr.ScAddress) string {
str, err := ScAddressToString(address)
if err != nil {
panic(err)
}
return str
}

func ScAddressToString(address *xdr.ScAddress) (string, error) {
if address == nil {
return "", nil
}

func ScAddressToString(address xdr.ScAddress) (string, error) {
var result string
var err error

Expand All @@ -47,53 +43,38 @@ func ScAddressToString(address *xdr.ScAddress) (string, error) {
return result, nil
}

func parseAddress(val *xdr.ScVal) *xdr.ScAddress {
if val == nil {
return nil
}

address, ok := val.GetObj()
if !ok || address == nil || address.Type != xdr.ScObjectTypeScoAddress {
return nil
}

return address.Address
}

func parseAmount(val *xdr.ScVal) *xdr.Int128Parts {
valueObj, ok := val.GetObj()
if !ok || valueObj == nil || valueObj.Type != xdr.ScObjectTypeScoI128 {
return nil
}

return valueObj.I128
}

// parseBalanceChangeEvent is a generalization of a subset of the Stellar Asset
// Contract events. Transfer, mint, clawback, and burn events all have two
// addresses and an amount involved. The addresses represent different things in
// different event types (e.g. "from" or "admin"), but the parsing is identical.
// This helper extracts all three parts or returns a generic error if it can't.
func parseBalanceChangeEvent(topics xdr.ScVec, value xdr.ScVal) (string, string, xdr.Int128Parts, error) {
first, second, amount := "", "", xdr.Int128Parts{}

func parseBalanceChangeEvent(topics xdr.ScVec, value xdr.ScVal) (
first string,
second string,
amount xdr.Int128Parts,
err error,
) {
err = ErrNotBalanceChangeEvent
if len(topics) != 4 {
return first, second, amount, ErrNotBalanceChangeEvent
return
}

rawFirst, rawSecond := topics[1], topics[2]
firstSc, secondSc := parseAddress(&rawFirst), parseAddress(&rawSecond)
if firstSc == nil || secondSc == nil {
return first, second, amount, ErrNotBalanceChangeEvent
firstSc, ok := topics[1].GetAddress()
if !ok {
return
}
first = MustScAddressToString(firstSc)

first, second = MustScAddressToString(firstSc), MustScAddressToString(secondSc)
secondSc, ok := topics[2].GetAddress()
if !ok {
return
}
second = MustScAddressToString(secondSc)

amountPtr := parseAmount(&value)
if amountPtr == nil {
return first, second, amount, ErrNotBalanceChangeEvent
amount, ok = value.GetI128()
if !ok {
return
}

amount = *amountPtr
return first, second, amount, nil
}