diff --git a/common/types/offer_test.go b/common/types/offer_test.go index e9dc0d4b..a405c4f8 100644 --- a/common/types/offer_test.go +++ b/common/types/offer_test.go @@ -12,6 +12,7 @@ import ( "github.com/stretchr/testify/require" "github.com/athanorlabs/atomic-swap/coins" + "github.com/athanorlabs/atomic-swap/common/vjson" ) func TestOffer_MarshalJSON(t *testing.T) { @@ -31,7 +32,7 @@ func TestOffer_MarshalJSON(t *testing.T) { "ethAsset": "ETH", "nonce": %d }`, offer.ID, offer.Nonce) - jsonData, err := json.Marshal(offer) + jsonData, err := vjson.MarshalStruct(offer) require.NoError(t, err) require.JSONEq(t, expected, string(jsonData)) } @@ -105,7 +106,7 @@ func TestOffer_MarshalJSON_RoundTrip(t *testing.T) { max := apd.New(200, 0) rate := coins.ToExchangeRate(apd.New(15, -1)) // 1.5 offer1 := NewOffer(coins.ProvidesXMR, min, max, rate, EthAssetETH) - offerJSON, err := json.Marshal(offer1) + offerJSON, err := vjson.MarshalStruct(offer1) require.NoError(t, err) var offer2 Offer err = json.Unmarshal(offerJSON, &offer2) diff --git a/common/vjson/validated_json.go b/common/vjson/validated_json.go new file mode 100644 index 00000000..25a98826 --- /dev/null +++ b/common/vjson/validated_json.go @@ -0,0 +1,38 @@ +package vjson + +import ( + "encoding/json" + + "github.com/go-playground/validator/v10" +) + +// Documentation on the validator package is here: +// https://pkg.go.dev/github.com/go-playground/validator/v10 +var validate = validator.New() + +// MarshalStruct adds additional validation on top of json.Marshal. Input type +// should be a struct pointer. +func MarshalStruct(v any) ([]byte, error) { + if err := validate.Struct(v); err != nil { + return nil, err + } + return json.Marshal(v) +} + +// MarshalIndentStruct adds additional validation on top of json.MarshalIndent. +// Input type should be a struct pointer. +func MarshalIndentStruct(v any, prefix, indent string) ([]byte, error) { + if err := validate.Struct(v); err != nil { + return nil, err + } + return json.MarshalIndent(v, prefix, indent) +} + +// UnmarshalStruct adds additional validation on top of json.Unmarshal. Target +// object be a struct pointer. +func UnmarshalStruct(jsonData []byte, v any) error { + if err := json.Unmarshal(jsonData, v); err != nil { + return err + } + return validate.Struct(v) +} diff --git a/common/vjson/validated_json_test.go b/common/vjson/validated_json_test.go new file mode 100644 index 00000000..e5605566 --- /dev/null +++ b/common/vjson/validated_json_test.go @@ -0,0 +1,54 @@ +// Package vjson or "validated JSON" provides additional validation, configured +// via annotations, on structures as they are Marshaled or Unmarshalled to/from +// JSON data. +package vjson + +import ( + "testing" + + "github.com/cockroachdb/apd/v3" + "github.com/stretchr/testify/require" +) + +type SomeStruct struct { + Decimal *apd.Decimal `json:"decimal" validate:"required"` + Hex string `json:"hex,omitempty" validate:"omitempty,hexadecimal"` +} + +func TestMarshalStruct(t *testing.T) { + s := &SomeStruct{Decimal: apd.New(11, -1)} + + data, err := MarshalStruct(s) + require.NoError(t, err) + require.Equal(t, `{"decimal":"1.1"}`, string(data)) + + data, err = MarshalIndentStruct(s, "", " ") + require.NoError(t, err) + require.Equal(t, "{\n \"decimal\": \"1.1\"\n}", string(data)) +} + +func TestMarshalStruct_notValid(t *testing.T) { + s := &SomeStruct{Decimal: nil} + errMsg := `'SomeStruct.Decimal' Error:Field validation for 'Decimal' failed on the 'required' tag` + + _, err := MarshalStruct(s) + require.Error(t, err) + require.ErrorContains(t, err, errMsg) + + _, err = MarshalIndentStruct(s, "", " ") + require.Error(t, err) + require.ErrorContains(t, err, errMsg) +} + +func TestUnmarshalStruct(t *testing.T) { + var s = new(SomeStruct) + err := UnmarshalStruct([]byte(`{"decimal":"0","hex":"0x12ab"}`), s) + require.NoError(t, err) +} + +func TestUnmarshalStruct_notValid(t *testing.T) { + var s = new(SomeStruct) + err := UnmarshalStruct([]byte(`{"decimal":"0","hex":"xyz"}`), s) + errMsg := `Key: 'SomeStruct.Hex' Error:Field validation for 'Hex' failed on the 'hexadecimal' tag` + require.ErrorContains(t, err, errMsg) +} diff --git a/db/database.go b/db/database.go index 6c15f6b3..afbf0307 100644 --- a/db/database.go +++ b/db/database.go @@ -2,13 +2,13 @@ package db import ( - "encoding/json" "errors" "github.com/ChainSafe/chaindb" logging "github.com/ipfs/go-log" "github.com/athanorlabs/atomic-swap/common/types" + "github.com/athanorlabs/atomic-swap/common/vjson" "github.com/athanorlabs/atomic-swap/protocol/swap" ) @@ -83,7 +83,7 @@ func (db *Database) RecoveryDB() *RecoveryDB { // PutOffer puts an offer in the database. func (db *Database) PutOffer(offer *types.Offer) error { - val, err := json.Marshal(offer) + val, err := vjson.MarshalStruct(offer) if err != nil { return err } @@ -182,7 +182,7 @@ func (db *Database) ClearAllOffers() error { // PutSwap puts the given swap in the database. // If a swap with the same ID is already in the database, it overwrites it. func (db *Database) PutSwap(s *swap.Info) error { - val, err := json.Marshal(s) + val, err := vjson.MarshalStruct(s) if err != nil { return err } @@ -205,7 +205,7 @@ func (db *Database) GetSwap(id types.Hash) (*swap.Info, error) { } var s swap.Info - err = json.Unmarshal(value, &s) + err = vjson.UnmarshalStruct(value, &s) if err != nil { return nil, err } diff --git a/db/recovery_db.go b/db/recovery_db.go index fa408a5e..b886a3f5 100644 --- a/db/recovery_db.go +++ b/db/recovery_db.go @@ -1,9 +1,8 @@ package db import ( - "encoding/json" - "github.com/athanorlabs/atomic-swap/common/types" + "github.com/athanorlabs/atomic-swap/common/vjson" mcrypto "github.com/athanorlabs/atomic-swap/crypto/monero" "github.com/ChainSafe/chaindb" @@ -40,7 +39,7 @@ func (db *RecoveryDB) close() error { // PutSwapRelayerInfo ... func (db *RecoveryDB) PutSwapRelayerInfo(id types.Hash, info *types.OfferExtra) error { - val, err := json.Marshal(info) + val, err := vjson.MarshalStruct(info) if err != nil { return err } @@ -58,7 +57,7 @@ func (db *RecoveryDB) GetSwapRelayerInfo(id types.Hash) (*types.OfferExtra, erro } var s types.OfferExtra - err = json.Unmarshal(value, &s) + err = vjson.UnmarshalStruct(value, &s) if err != nil { return nil, err } @@ -70,7 +69,7 @@ func (db *RecoveryDB) GetSwapRelayerInfo(id types.Hash) (*types.OfferExtra, erro // swap ID, but is instead a hash of the `SwapFactorySwap` structure) // and contract swap structure for the given swap ID. func (db *RecoveryDB) PutContractSwapInfo(id types.Hash, info *EthereumSwapInfo) error { - val, err := json.Marshal(info) + val, err := vjson.MarshalStruct(info) if err != nil { return err } @@ -89,7 +88,7 @@ func (db *RecoveryDB) GetContractSwapInfo(id types.Hash) (*EthereumSwapInfo, err } var s EthereumSwapInfo - err = json.Unmarshal(value, &s) + err = vjson.UnmarshalStruct(value, &s) if err != nil { return nil, err } @@ -99,7 +98,7 @@ func (db *RecoveryDB) GetContractSwapInfo(id types.Hash) (*EthereumSwapInfo, err // PutSwapPrivateKey stores the given ephemeral swap private key share for the given swap ID. func (db *RecoveryDB) PutSwapPrivateKey(id types.Hash, sk *mcrypto.PrivateSpendKey) error { - val, err := json.Marshal(sk) + val, err := vjson.MarshalStruct(sk) if err != nil { return err } @@ -117,7 +116,7 @@ func (db *RecoveryDB) GetSwapPrivateKey(id types.Hash) (*mcrypto.PrivateSpendKey } privSpendKey := new(mcrypto.PrivateSpendKey) - err = json.Unmarshal(value, privSpendKey) + err = vjson.UnmarshalStruct(value, privSpendKey) if err != nil { return nil, err } @@ -127,7 +126,7 @@ func (db *RecoveryDB) GetSwapPrivateKey(id types.Hash) (*mcrypto.PrivateSpendKey // PutCounterpartySwapPrivateKey stores the counterparty's swap private key for the given swap ID. func (db *RecoveryDB) PutCounterpartySwapPrivateKey(id types.Hash, kp *mcrypto.PrivateSpendKey) error { - val, err := json.Marshal(kp) + val, err := vjson.MarshalStruct(kp) if err != nil { return err } @@ -145,7 +144,7 @@ func (db *RecoveryDB) GetCounterpartySwapPrivateKey(id types.Hash) (*mcrypto.Pri } sk := new(mcrypto.PrivateSpendKey) - err = json.Unmarshal(value, sk) + err = vjson.UnmarshalStruct(value, sk) if err != nil { return nil, err } @@ -154,15 +153,15 @@ func (db *RecoveryDB) GetCounterpartySwapPrivateKey(id types.Hash) (*mcrypto.Pri } type xmrmakerKeys struct { - PublicSpendKey mcrypto.PublicKey `json:"publicSpendKey"` - PrivateViewKey mcrypto.PrivateViewKey `json:"privateViewKey"` + PublicSpendKey *mcrypto.PublicKey `json:"publicSpendKey" validate:"required"` + PrivateViewKey *mcrypto.PrivateViewKey `json:"privateViewKey" validate:"required"` } // PutXMRMakerSwapKeys is called by the xmrtaker to store the counterparty's swap keys. func (db *RecoveryDB) PutXMRMakerSwapKeys(id types.Hash, sk *mcrypto.PublicKey, vk *mcrypto.PrivateViewKey) error { - val, err := json.Marshal(&xmrmakerKeys{ - PublicSpendKey: *sk, - PrivateViewKey: *vk, + val, err := vjson.MarshalStruct(&xmrmakerKeys{ + PublicSpendKey: sk, + PrivateViewKey: vk, }) if err != nil { return err @@ -176,18 +175,18 @@ func (db *RecoveryDB) PutXMRMakerSwapKeys(id types.Hash, sk *mcrypto.PublicKey, // swap keys. func (db *RecoveryDB) GetXMRMakerSwapKeys(id types.Hash) (*mcrypto.PublicKey, *mcrypto.PrivateViewKey, error) { key := getRecoveryDBKey(id, xmrmakerKeysPrefix) - value, err := db.db.Get(key[:]) + value, err := db.db.Get(key) if err != nil { return nil, nil, err } var info xmrmakerKeys - err = json.Unmarshal(value, &info) + err = vjson.UnmarshalStruct(value, &info) if err != nil { return nil, nil, err } - return &info.PublicSpendKey, &info.PrivateViewKey, nil + return info.PublicSpendKey, info.PrivateViewKey, nil } // DeleteSwap deletes all recovery info from the db for the given swap. diff --git a/db/recovery_db_test.go b/db/recovery_db_test.go index 454c9810..eeba1026 100644 --- a/db/recovery_db_test.go +++ b/db/recovery_db_test.go @@ -1,7 +1,6 @@ package db import ( - "encoding/json" "math/big" "testing" @@ -12,6 +11,7 @@ import ( "github.com/athanorlabs/atomic-swap/coins" "github.com/athanorlabs/atomic-swap/common/types" + "github.com/athanorlabs/atomic-swap/common/vjson" mcrypto "github.com/athanorlabs/atomic-swap/crypto/monero" contracts "github.com/athanorlabs/atomic-swap/ethereum" ) @@ -65,7 +65,7 @@ func TestRecoveryDB_ContractSwapInfo(t *testing.T) { }, "contract_address": "0xd2b5d6252d0645e4cf4bb547e82a485f527befb7" }` - jsonData, err := json.Marshal(si) + jsonData, err := vjson.MarshalStruct(si) require.NoError(t, err) require.JSONEq(t, expectedStr, string(jsonData)) diff --git a/ethereum/swap_factory_marshal.go b/ethereum/swap_factory_marshal.go index 8fd99832..2fefff9c 100644 --- a/ethereum/swap_factory_marshal.go +++ b/ethereum/swap_factory_marshal.go @@ -1,12 +1,12 @@ package contracts import ( - "encoding/json" "math/big" "github.com/ethereum/go-ethereum/common" "github.com/athanorlabs/atomic-swap/common/types" + "github.com/athanorlabs/atomic-swap/common/vjson" ) // swap is the same as the auto-generated SwapFactorySwap type, but with some type @@ -16,16 +16,16 @@ type swap struct { Claimer common.Address `json:"claimer"` PubKeyClaim types.Hash `json:"pub_key_claim"` PubKeyRefund types.Hash `json:"pub_key_refund"` - Timeout0 *big.Int `json:"timeout0"` - Timeout1 *big.Int `json:"timeout1"` + Timeout0 *big.Int `json:"timeout0" validate:"required"` + Timeout1 *big.Int `json:"timeout1" validate:"required"` Asset common.Address `json:"asset"` - Value *big.Int `json:"value"` - Nonce *big.Int `json:"nonce"` + Value *big.Int `json:"value" validate:"required"` + Nonce *big.Int `json:"nonce" validate:"required"` } // MarshalJSON provides JSON marshalling for SwapFactorySwap func (sfs *SwapFactorySwap) MarshalJSON() ([]byte, error) { - return json.Marshal(&swap{ + return vjson.MarshalStruct(&swap{ Owner: sfs.Owner, Claimer: sfs.Claimer, PubKeyClaim: sfs.PubKeyClaim, @@ -41,7 +41,7 @@ func (sfs *SwapFactorySwap) MarshalJSON() ([]byte, error) { // UnmarshalJSON provides JSON unmarshalling for SwapFactorySwap func (sfs *SwapFactorySwap) UnmarshalJSON(data []byte) error { s := &swap{} - if err := json.Unmarshal(data, s); err != nil { + if err := vjson.UnmarshalStruct(data, s); err != nil { return err } *sfs = SwapFactorySwap{ diff --git a/ethereum/swap_factory_marshal_test.go b/ethereum/swap_factory_marshal_test.go index 2e02f862..804d40d4 100644 --- a/ethereum/swap_factory_marshal_test.go +++ b/ethereum/swap_factory_marshal_test.go @@ -11,6 +11,7 @@ import ( "github.com/stretchr/testify/require" "github.com/athanorlabs/atomic-swap/coins" + "github.com/athanorlabs/atomic-swap/common/vjson" ) func TestSwapFactorySwap_JSON(t *testing.T) { @@ -36,7 +37,7 @@ func TestSwapFactorySwap_JSON(t *testing.T) { "value": 9876000000000000000000, "nonce": 1234 }` - jsonData, err := json.Marshal(sf) + jsonData, err := vjson.MarshalStruct(sf) require.NoError(t, err) require.JSONEq(t, expectedJSON, string(jsonData)) diff --git a/go.mod b/go.mod index 13b7b9bb..39f48f62 100644 --- a/go.mod +++ b/go.mod @@ -16,6 +16,7 @@ require ( github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 github.com/ethereum/go-ethereum v1.10.26 github.com/fatih/color v1.14.1 + github.com/go-playground/validator/v10 v10.11.2 github.com/golang/mock v1.6.0 github.com/gorilla/handlers v1.5.1 github.com/gorilla/mux v1.8.0 @@ -54,6 +55,8 @@ require ( github.com/francoispqt/gojay v1.2.13 // indirect github.com/gabstv/httpdigest v0.0.0-20200601123255-912d52c2d608 // indirect github.com/go-ole/go-ole v1.2.6 // indirect + github.com/go-playground/locales v0.14.1 // indirect + github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-stack/stack v1.8.1 // indirect github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect github.com/godbus/dbus/v5 v5.1.0 // indirect @@ -82,6 +85,7 @@ require ( github.com/klauspost/compress v1.15.12 // indirect github.com/klauspost/cpuid/v2 v2.2.2 // indirect github.com/koron/go-ssdp v0.0.3 // indirect + github.com/leodido/go-urn v1.2.1 // indirect github.com/libp2p/go-buffer-pool v0.1.0 // indirect github.com/libp2p/go-cidranger v1.1.0 // indirect github.com/libp2p/go-flow-metrics v0.1.0 // indirect @@ -153,6 +157,7 @@ require ( golang.org/x/mod v0.7.0 // indirect golang.org/x/net v0.5.0 // indirect golang.org/x/sync v0.1.0 // indirect + golang.org/x/text v0.6.0 // indirect golang.org/x/tools v0.3.0 // indirect google.golang.org/protobuf v1.28.1 // indirect gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect diff --git a/go.sum b/go.sum index 12dd5e13..b326b98d 100644 --- a/go.sum +++ b/go.sum @@ -210,6 +210,13 @@ github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KE github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-playground/validator/v10 v10.11.2 h1:q3SHpufmypg+erIExEKUmsgmhDTyhcJ38oeKGACXohU= +github.com/go-playground/validator/v10 v10.11.2/go.mod h1:NieE624vt4SCTJtD87arVLvdmjPAeV8BQlHtMnw9D7s= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw= github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4= @@ -405,6 +412,8 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= +github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw= github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8= github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= @@ -592,7 +601,7 @@ github.com/rivo/uniseg v0.4.2 h1:YwD0ulJSJytLpiaWua0sBDusfsCZohxjxzVTYjwxfV8= github.com/rjeczalik/notify v0.9.3 h1:6rJAzHTGKXGj76sbRgDiDcYj/HniypXmSJo1SWakZeY= github.com/rjeczalik/notify v0.9.3/go.mod h1:gF3zSOrafR9DQEWSE8TjfI9NkooDxbyT4UgRGKZA0lc= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= +github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= @@ -654,6 +663,7 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= @@ -914,6 +924,7 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.6.0 h1:3XmdazWV+ubf7QgHSTWeykHOci5oeekaGJBLkrkaw4k= +golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= diff --git a/net/host.go b/net/host.go index b553c034..2df9c336 100644 --- a/net/host.go +++ b/net/host.go @@ -24,7 +24,7 @@ const ( maxMessageSize = 1 << 17 ) -var log = logging.Logger("host") +var log = logging.Logger("net") // P2pHost contains libp2p functionality used by the Host. type P2pHost interface { diff --git a/net/host_test.go b/net/host_test.go index 1e4da661..540f36ae 100644 --- a/net/host_test.go +++ b/net/host_test.go @@ -20,6 +20,7 @@ func init() { var testID = types.Hash{99} type mockHandler struct { + t *testing.T id types.Hash } @@ -27,11 +28,11 @@ func (h *mockHandler) GetOffers() []*types.Offer { return []*types.Offer{} } -func (h *mockHandler) HandleInitiateMessage(_ *message.SendKeysMessage) (s SwapState, resp Message, err error) { +func (h *mockHandler) HandleInitiateMessage(msg *message.SendKeysMessage) (s SwapState, resp Message, err error) { if (h.id != types.Hash{}) { - return &mockSwapState{h.id}, &SendKeysMessage{}, nil + return &mockSwapState{h.id}, createSendKeysMessage(h.t), nil } - return &mockSwapState{}, &SendKeysMessage{}, nil + return &mockSwapState{}, msg, nil } type mockSwapState struct { @@ -71,7 +72,7 @@ func basicTestConfig(t *testing.T) *p2pnet.Config { func newHost(t *testing.T, cfg *p2pnet.Config) *Host { h, err := NewHost(cfg) require.NoError(t, err) - h.SetHandler(&mockHandler{}) + h.SetHandler(&mockHandler{t: t}) t.Cleanup(func() { err = h.Stop() require.NoError(t, err) diff --git a/net/initiate_test.go b/net/initiate_test.go index d2dfb559..b293c8be 100644 --- a/net/initiate_test.go +++ b/net/initiate_test.go @@ -1,14 +1,35 @@ package net import ( + "encoding/hex" "testing" "time" + "github.com/cockroachdb/apd/v3" + ethcommon "github.com/ethereum/go-ethereum/common" + "github.com/athanorlabs/atomic-swap/common/types" + "github.com/athanorlabs/atomic-swap/net/message" + pcommon "github.com/athanorlabs/atomic-swap/protocol" "github.com/stretchr/testify/require" ) +func createSendKeysMessage(t *testing.T) *message.SendKeysMessage { + keysAndProof, err := pcommon.GenerateKeysAndProof() + require.NoError(t, err) + return &message.SendKeysMessage{ + OfferID: types.Hash{}, + ProvidedAmount: new(apd.Decimal), + PublicSpendKey: keysAndProof.PublicKeyPair.SpendKey(), + PublicViewKey: keysAndProof.PublicKeyPair.ViewKey(), + PrivateViewKey: keysAndProof.PrivateKeyPair.ViewKey(), + DLEqProof: hex.EncodeToString(keysAndProof.DLEqProof.Proof()), + Secp256k1PublicKey: keysAndProof.Secp256k1PublicKey, + EthAddress: ethcommon.Address{}, + } +} + func TestHost_Initiate(t *testing.T) { ha := newHost(t, basicTestConfig(t)) err := ha.Start() @@ -20,11 +41,17 @@ func TestHost_Initiate(t *testing.T) { err = ha.h.Connect(ha.ctx, hb.h.AddrInfo()) require.NoError(t, err) - err = ha.Initiate(hb.h.AddrInfo(), &SendKeysMessage{}, new(mockSwapState)) + err = ha.Initiate(hb.h.AddrInfo(), createSendKeysMessage(t), new(mockSwapState)) require.NoError(t, err) time.Sleep(time.Millisecond * 500) + + ha.swapMu.Lock() require.NotNil(t, ha.swaps[testID]) + ha.swapMu.Unlock() + + hb.swapMu.Lock() require.NotNil(t, hb.swaps[testID]) + hb.swapMu.Unlock() } func TestHost_ConcurrentSwaps(t *testing.T) { @@ -43,17 +70,29 @@ func TestHost_ConcurrentSwaps(t *testing.T) { err = ha.h.Connect(ha.ctx, hb.h.AddrInfo()) require.NoError(t, err) - err = ha.Initiate(hb.h.AddrInfo(), &SendKeysMessage{}, new(mockSwapState)) + err = ha.Initiate(hb.h.AddrInfo(), createSendKeysMessage(t), new(mockSwapState)) require.NoError(t, err) time.Sleep(time.Millisecond * 500) + + ha.swapMu.Lock() require.NotNil(t, ha.swaps[testID]) + ha.swapMu.Unlock() + + hb.swapMu.Lock() require.NotNil(t, hb.swaps[testID]) + hb.swapMu.Unlock() hb.handler.(*mockHandler).id = testID2 - err = ha.Initiate(hb.h.AddrInfo(), &SendKeysMessage{}, &mockSwapState{testID2}) + err = ha.Initiate(hb.h.AddrInfo(), createSendKeysMessage(t), &mockSwapState{testID2}) require.NoError(t, err) time.Sleep(time.Millisecond * 1500) - require.NotNil(t, ha.swaps[testID2]) - require.NotNil(t, hb.swaps[testID2]) + + ha.swapMu.Lock() + require.NotNil(t, ha.swaps[testID]) + ha.swapMu.Unlock() + + hb.swapMu.Lock() + require.NotNil(t, hb.swaps[testID]) + hb.swapMu.Unlock() } diff --git a/net/message/message.go b/net/message/message.go index f1c7e3a9..ea0337fa 100644 --- a/net/message/message.go +++ b/net/message/message.go @@ -2,7 +2,6 @@ package message import ( - "encoding/json" "errors" "fmt" @@ -11,6 +10,7 @@ import ( "github.com/athanorlabs/atomic-swap/common" "github.com/athanorlabs/atomic-swap/common/types" + "github.com/athanorlabs/atomic-swap/common/vjson" mcrypto "github.com/athanorlabs/atomic-swap/crypto/monero" "github.com/athanorlabs/atomic-swap/crypto/secp256k1" contracts "github.com/athanorlabs/atomic-swap/ethereum" @@ -65,7 +65,7 @@ func DecodeMessage(b []byte) (common.Message, error) { return nil, fmt.Errorf("invalid message type=%d", msgType) } - if err := json.Unmarshal(msgJSON, &msg); err != nil { + if err := vjson.UnmarshalStruct(msgJSON, msg); err != nil { return nil, fmt.Errorf("failed to decode %s message: %w", TypeToString(msg.Type()), err) } return msg, nil @@ -73,7 +73,7 @@ func DecodeMessage(b []byte) (common.Message, error) { // QueryResponse ... type QueryResponse struct { - Offers []*types.Offer `json:"offers"` + Offers []*types.Offer `json:"offers" validate:"dive,required"` } // String ... @@ -85,7 +85,7 @@ func (m *QueryResponse) String() string { // Encode ... func (m *QueryResponse) Encode() ([]byte, error) { - b, err := json.Marshal(m) + b, err := vjson.MarshalStruct(m) if err != nil { return nil, err } @@ -104,12 +104,12 @@ func (m *QueryResponse) Type() byte { // SendKeysMessage is sent by both parties to each other to initiate the protocol type SendKeysMessage struct { OfferID types.Hash `json:"offerID"` - ProvidedAmount *apd.Decimal `json:"providedAmount"` - PublicSpendKey *mcrypto.PublicKey `json:"publicSpendKey"` + ProvidedAmount *apd.Decimal `json:"providedAmount" validate:"required"` + PublicSpendKey *mcrypto.PublicKey `json:"publicSpendKey" validate:"required"` PublicViewKey *mcrypto.PublicKey `json:"publicViewKey"` PrivateViewKey *mcrypto.PrivateViewKey `json:"privateViewKey"` - DLEqProof string `json:"dleqProof"` - Secp256k1PublicKey *secp256k1.PublicKey `json:"secp256k1PublicKey"` + DLEqProof string `json:"dleqProof" validate:"required"` + Secp256k1PublicKey *secp256k1.PublicKey `json:"secp256k1PublicKey" validate:"required"` EthAddress ethcommon.Address `json:"ethAddress"` } @@ -129,7 +129,7 @@ func (m *SendKeysMessage) String() string { // Encode ... func (m *SendKeysMessage) Encode() ([]byte, error) { - b, err := json.Marshal(m) + b, err := vjson.MarshalStruct(m) if err != nil { return nil, err } @@ -148,7 +148,7 @@ type NotifyETHLocked struct { Address ethcommon.Address `json:"address"` TxHash types.Hash `json:"txHash"` ContractSwapID types.Hash `json:"contractSwapID"` - ContractSwap *contracts.SwapFactorySwap `json:"contractSwap"` + ContractSwap *contracts.SwapFactorySwap `json:"contractSwap" validate:"required"` } // String ... @@ -163,7 +163,7 @@ func (m *NotifyETHLocked) String() string { // Encode ... func (m *NotifyETHLocked) Encode() ([]byte, error) { - b, err := json.Marshal(m) + b, err := vjson.MarshalStruct(m) if err != nil { return nil, err } @@ -178,8 +178,8 @@ func (m *NotifyETHLocked) Type() byte { // NotifyXMRLock is sent by XMRMaker to XMRTaker after locking his XMR. type NotifyXMRLock struct { - Address string `json:"address"` // address the monero was sent to - TxID types.Hash `json:"txID"` // Monero transaction ID (transaction hash in hex) + Address string `json:"address" validate:"required"` // address the monero was sent to + TxID types.Hash `json:"txID"` // Monero transaction ID (transaction hash in hex) } // String ... @@ -189,7 +189,7 @@ func (m *NotifyXMRLock) String() string { // Encode ... func (m *NotifyXMRLock) Encode() ([]byte, error) { - b, err := json.Marshal(m) + b, err := vjson.MarshalStruct(m) if err != nil { return nil, err } diff --git a/protocol/swap/types_test.go b/protocol/swap/types_test.go index 182e1b40..18aada95 100644 --- a/protocol/swap/types_test.go +++ b/protocol/swap/types_test.go @@ -1,7 +1,6 @@ package swap import ( - "encoding/json" "fmt" "testing" @@ -11,6 +10,7 @@ import ( "github.com/athanorlabs/atomic-swap/coins" "github.com/athanorlabs/atomic-swap/common/types" + "github.com/athanorlabs/atomic-swap/common/vjson" ) func Test_InfoMarshal(t *testing.T) { @@ -27,7 +27,7 @@ func Test_InfoMarshal(t *testing.T) { 200, make(chan types.Status), ) - infoBytes, err := json.Marshal(info) + infoBytes, err := vjson.MarshalStruct(info) require.NoError(t, err) expectedJSON := `{ "version": "0.2.0", diff --git a/rpc/ws.go b/rpc/ws.go index 9781866a..70914a26 100644 --- a/rpc/ws.go +++ b/rpc/ws.go @@ -2,7 +2,6 @@ package rpc import ( "context" - "encoding/json" "fmt" "net/http" "time" @@ -10,6 +9,7 @@ import ( "github.com/athanorlabs/atomic-swap/common" "github.com/athanorlabs/atomic-swap/common/rpctypes" "github.com/athanorlabs/atomic-swap/common/types" + "github.com/athanorlabs/atomic-swap/common/vjson" mcrypto "github.com/athanorlabs/atomic-swap/crypto/monero" ethcommon "github.com/ethereum/go-ethereum/common" @@ -62,8 +62,8 @@ func (s *wsServer) ServeHTTP(w http.ResponseWriter, r *http.Request) { break } - var req *rpctypes.Request - err = json.Unmarshal(message, &req) + req := new(rpctypes.Request) + err = vjson.UnmarshalStruct(message, req) if err != nil { _ = writeError(conn, err) continue @@ -80,8 +80,8 @@ func (s *wsServer) ServeHTTP(w http.ResponseWriter, r *http.Request) { func (s *wsServer) handleRequest(conn *websocket.Conn, req *rpctypes.Request) error { switch req.Method { case rpctypes.SubscribeSigner: - var params *rpctypes.SignerRequest - if err := json.Unmarshal(req.Params, ¶ms); err != nil { + params := new(rpctypes.SignerRequest) + if err := vjson.UnmarshalStruct(req.Params, params); err != nil { return fmt.Errorf("failed to unmarshal parameters: %w", err) } @@ -89,8 +89,8 @@ func (s *wsServer) handleRequest(conn *websocket.Conn, req *rpctypes.Request) er case rpctypes.SubscribeNewPeer: return errUnimplemented case rpctypes.NetDiscover: - var params *rpctypes.DiscoverRequest - if err := json.Unmarshal(req.Params, ¶ms); err != nil { + params := new(rpctypes.DiscoverRequest) + if err := vjson.UnmarshalStruct(req.Params, params); err != nil { return fmt.Errorf("failed to unmarshal parameters: %w", err) } @@ -102,8 +102,8 @@ func (s *wsServer) handleRequest(conn *websocket.Conn, req *rpctypes.Request) er return writeResponse(conn, resp) case rpctypes.NetQueryPeer: - var params *rpctypes.QueryPeerRequest - if err := json.Unmarshal(req.Params, ¶ms); err != nil { + params := new(rpctypes.QueryPeerRequest) + if err := vjson.UnmarshalStruct(req.Params, params); err != nil { return fmt.Errorf("failed to unmarshal parameters: %w", err) } @@ -115,15 +115,15 @@ func (s *wsServer) handleRequest(conn *websocket.Conn, req *rpctypes.Request) er return writeResponse(conn, resp) case rpctypes.SubscribeSwapStatus: - var params *rpctypes.SubscribeSwapStatusRequest - if err := json.Unmarshal(req.Params, ¶ms); err != nil { + params := new(rpctypes.SubscribeSwapStatusRequest) + if err := vjson.UnmarshalStruct(req.Params, params); err != nil { return fmt.Errorf("failed to unmarshal parameters: %w", err) } return s.subscribeSwapStatus(s.ctx, conn, params.OfferID) case rpctypes.SubscribeTakeOffer: - var params *rpctypes.TakeOfferRequest - if err := json.Unmarshal(req.Params, ¶ms); err != nil { + params := new(rpctypes.TakeOfferRequest) + if err := vjson.UnmarshalStruct(req.Params, params); err != nil { return fmt.Errorf("failed to unmarshal parameters: %w", err) } @@ -134,8 +134,8 @@ func (s *wsServer) handleRequest(conn *websocket.Conn, req *rpctypes.Request) er return s.subscribeTakeOffer(s.ctx, conn, ch) case rpctypes.SubscribeMakeOffer: - var params *rpctypes.MakeOfferRequest - if err := json.Unmarshal(req.Params, ¶ms); err != nil { + params := new(rpctypes.MakeOfferRequest) + if err := vjson.UnmarshalStruct(req.Params, params); err != nil { return fmt.Errorf("failed to unmarshal parameters: %w", err) } @@ -203,8 +203,8 @@ func (s *wsServer) handleSigner(ctx context.Context, conn *websocket.Conn, offer return err } - var params *rpctypes.SignerTxSigned - if err := json.Unmarshal(message, ¶ms); err != nil { + params := new(rpctypes.SignerTxSigned) + if err := vjson.UnmarshalStruct(message, ¶ms); err != nil { return fmt.Errorf("failed to unmarshal parameters: %w", err) } @@ -332,7 +332,7 @@ func (s *wsServer) writeSwapExitStatus(conn *websocket.Conn, id types.Hash) erro } func writeResponse(conn *websocket.Conn, result interface{}) error { - bz, err := json.Marshal(result) + bz, err := vjson.MarshalStruct(result) if err != nil { return err } diff --git a/rpcclient/wsclient/wsclient.go b/rpcclient/wsclient/wsclient.go index 3e49e986..5371d649 100644 --- a/rpcclient/wsclient/wsclient.go +++ b/rpcclient/wsclient/wsclient.go @@ -4,7 +4,6 @@ package wsclient import ( "context" - "encoding/json" "fmt" "sync" @@ -14,6 +13,7 @@ import ( "github.com/athanorlabs/atomic-swap/coins" "github.com/athanorlabs/atomic-swap/common/rpctypes" "github.com/athanorlabs/atomic-swap/common/types" + "github.com/athanorlabs/atomic-swap/common/vjson" "github.com/gorilla/websocket" logging "github.com/ipfs/go-log" @@ -90,7 +90,7 @@ func (c *wsClient) Discover(provides string, searchTime uint64) ([]peer.ID, erro SearchTime: searchTime, } - bz, err := json.Marshal(params) + bz, err := vjson.MarshalStruct(params) if err != nil { return nil, err } @@ -111,8 +111,8 @@ func (c *wsClient) Discover(provides string, searchTime uint64) ([]peer.ID, erro return nil, fmt.Errorf("failed to read websockets message: %s", err) } - var resp *rpctypes.Response - err = json.Unmarshal(message, &resp) + resp := new(rpctypes.Response) + err = vjson.UnmarshalStruct(message, resp) if err != nil { return nil, fmt.Errorf("failed to unmarshal response: %w", err) } @@ -122,8 +122,8 @@ func (c *wsClient) Discover(provides string, searchTime uint64) ([]peer.ID, erro } log.Debugf("received message over websockets: %s", message) - var dresp *rpctypes.DiscoverResponse - if err := json.Unmarshal(resp.Result, &dresp); err != nil { + dresp := new(rpctypes.DiscoverResponse) + if err := vjson.UnmarshalStruct(resp.Result, dresp); err != nil { return nil, fmt.Errorf("failed to unmarshal swap ID response: %s", err) } @@ -135,7 +135,7 @@ func (c *wsClient) Query(id peer.ID) (*rpctypes.QueryPeerResponse, error) { PeerID: id, } - bz, err := json.Marshal(params) + bz, err := vjson.MarshalStruct(params) if err != nil { return nil, err } @@ -157,8 +157,8 @@ func (c *wsClient) Query(id peer.ID) (*rpctypes.QueryPeerResponse, error) { return nil, fmt.Errorf("failed to read websockets message: %s", err) } - var resp *rpctypes.Response - err = json.Unmarshal(message, &resp) + resp := new(rpctypes.Response) + err = vjson.UnmarshalStruct(message, resp) if err != nil { return nil, fmt.Errorf("failed to unmarshal response: %w", err) } @@ -168,8 +168,8 @@ func (c *wsClient) Query(id peer.ID) (*rpctypes.QueryPeerResponse, error) { } log.Debugf("received message over websockets: %s", message) - var dresp *rpctypes.QueryPeerResponse - if err := json.Unmarshal(resp.Result, &dresp); err != nil { + dresp := new(rpctypes.QueryPeerResponse) + if err := vjson.UnmarshalStruct(resp.Result, dresp); err != nil { return nil, fmt.Errorf("failed to unmarshal swap ID response: %s", err) } @@ -183,7 +183,7 @@ func (c *wsClient) SubscribeSwapStatus(id types.Hash) (<-chan types.Status, erro OfferID: id, } - bz, err := json.Marshal(params) + bz, err := vjson.MarshalStruct(params) if err != nil { return nil, err } @@ -211,8 +211,8 @@ func (c *wsClient) SubscribeSwapStatus(id types.Hash) (<-chan types.Status, erro break } - var resp *rpctypes.Response - err = json.Unmarshal(message, &resp) + resp := new(rpctypes.Response) + err = vjson.UnmarshalStruct(message, resp) if err != nil { log.Warnf("failed to unmarshal response: %s", err) break @@ -224,8 +224,8 @@ func (c *wsClient) SubscribeSwapStatus(id types.Hash) (<-chan types.Status, erro } log.Debugf("received message over websockets: %s", message) - var status *rpctypes.SubscribeSwapStatusResponse - if err := json.Unmarshal(resp.Result, &status); err != nil { + status := new(rpctypes.SubscribeSwapStatusResponse) + if err := vjson.UnmarshalStruct(resp.Result, status); err != nil { log.Warnf("failed to unmarshal response: %s", err) break } @@ -252,7 +252,7 @@ func (c *wsClient) TakeOfferAndSubscribe( ProvidesAmount: providesAmount, } - bz, err := json.Marshal(params) + bz, err := vjson.MarshalStruct(params) if err != nil { return nil, err } @@ -303,8 +303,8 @@ func (c *wsClient) readTakeOfferResponse() (string, error) { return "", fmt.Errorf("failed to read websockets message: %s", err) } - var resp *rpctypes.Response - err = json.Unmarshal(message, &resp) + resp := new(rpctypes.Response) + err = vjson.UnmarshalStruct(message, resp) if err != nil { return "", fmt.Errorf("failed to unmarshal response: %w", err) } @@ -314,8 +314,8 @@ func (c *wsClient) readTakeOfferResponse() (string, error) { } log.Debugf("received message over websockets: %s", message) - var status *rpctypes.SubscribeSwapStatusResponse - if err := json.Unmarshal(resp.Result, &status); err != nil { + status := new(rpctypes.SubscribeSwapStatusResponse) + if err := vjson.UnmarshalStruct(resp.Result, status); err != nil { return "", fmt.Errorf("failed to unmarshal swap status response: %w", err) } @@ -339,7 +339,7 @@ func (c *wsClient) MakeOfferAndSubscribe( RelayerCommission: relayerCommission, } - bz, err := json.Marshal(params) + bz, err := vjson.MarshalStruct(params) if err != nil { return nil, nil, err } @@ -361,8 +361,8 @@ func (c *wsClient) MakeOfferAndSubscribe( return nil, nil, fmt.Errorf("failed to read websockets message: %s", err) } - var resp *rpctypes.Response - err = json.Unmarshal(message, &resp) + resp := new(rpctypes.Response) + err = vjson.UnmarshalStruct(message, resp) if err != nil { return nil, nil, fmt.Errorf("failed to unmarshal response: %w", err) } @@ -372,8 +372,8 @@ func (c *wsClient) MakeOfferAndSubscribe( } // read synchronous response (offer ID) - var respData *rpctypes.MakeOfferResponse - if err := json.Unmarshal(resp.Result, &respData); err != nil { + respData := new(rpctypes.MakeOfferResponse) + if err := vjson.UnmarshalStruct(resp.Result, respData); err != nil { return nil, nil, fmt.Errorf("failed to unmarshal response: %s", err) } @@ -389,8 +389,8 @@ func (c *wsClient) MakeOfferAndSubscribe( break } - var resp *rpctypes.Response - err = json.Unmarshal(message, &resp) + resp := new(rpctypes.Response) + err = vjson.UnmarshalStruct(message, resp) if err != nil { log.Warnf("failed to unmarshal response: %s", err) break @@ -402,8 +402,8 @@ func (c *wsClient) MakeOfferAndSubscribe( } log.Debugf("received message over websockets: %s", message) - var status *rpctypes.SubscribeSwapStatusResponse - if err := json.Unmarshal(resp.Result, &status); err != nil { + status := new(rpctypes.SubscribeSwapStatusResponse) + if err := vjson.UnmarshalStruct(resp.Result, status); err != nil { log.Warnf("failed to unmarshal response: %s", err) break } diff --git a/tests/erc20_integration_test.go b/tests/erc20_integration_test.go index fdd88304..47517104 100644 --- a/tests/erc20_integration_test.go +++ b/tests/erc20_integration_test.go @@ -33,8 +33,8 @@ func deployERC20Mock(t *testing.T) ethcommon.Address { pub := pkA.Public().(*ecdsa.PublicKey) addr := ethcrypto.PubkeyToAddress(*pub) - decimals := big.NewInt(0).Exp(big.NewInt(10), big.NewInt(18), nil) - balance := big.NewInt(0).Mul(big.NewInt(9999999), decimals) + decimals := new(big.Int).Exp(big.NewInt(10), big.NewInt(18), nil) + balance := new(big.Int).Mul(big.NewInt(9999999), decimals) erc20Addr, erc20Tx, _, err := contracts.DeployERC20Mock(auth, conn, "ERC20Mock", "MOCK", addr, balance) require.NoError(t, err) _, err = block.WaitForReceipt(context.Background(), conn, erc20Tx.Hash()) diff --git a/tests/integration_test.go b/tests/integration_test.go index 4d4fb92f..a1896f0a 100644 --- a/tests/integration_test.go +++ b/tests/integration_test.go @@ -697,7 +697,7 @@ func (s *IntegrationTestSuite) testAbortXMRMakerCancels(asset types.EthAsset) { default: } - common.SleepWithContext(ctx, 2*time.Second) // give some extra time for the offer to be re-added + common.SleepWithContext(ctx, 3*time.Second) // give some extra time for the offer to be re-added afterResp, err := bc.GetOffers() require.NoError(s.T(), err) require.Equal(s.T(), len(beforeResp.Offers), len(afterResp.Offers))