Giter VIP home page Giter VIP logo

go-xpx-chain-sdk's People

Contributors

alex-popov-tech avatar carlocayos avatar cempl avatar cyrillicw avatar iorhachovyevhen avatar jackshenn avatar jcn01 avatar jenyasd209 avatar mickeyscorsese avatar mrlsd avatar otsybizov avatar rachel-nml avatar ruellm avatar ruslanbik4 avatar sateetje avatar shinneng avatar slackve avatar st-wong avatar vadimdidenkogs avatar valerii-smirnov avatar wernling-proximax avatar wondertan avatar xgreenx avatar

Stargazers

 avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

go-xpx-chain-sdk's Issues

Websocket closing and handler race condition

When a handler is set to return true, it seems it will remove the function and the websocket will unsubscribe to channel if no more handler for same channel.

But if the websocket is closed right away after the handler execution, the unsubscription to channel will fail and results to panic.

	conf, err := sdk.NewConfig([]string{"http://csddev1.xpxsirius.io:3000", "http://csddev2.xpxsirius.io:3000"}, sdk.PrivateTest, sdk.WebsocketReconnectionDefaultTimeout)
	if err != nil {
		panic(err)
	}

	ctx, cancel := context.WithTimeout(context.TODO(), time.Second*30)
	//defer cancel()
	wsClient, err := websocket.NewClient(ctx, conf)
	if err != nil {
		panic(err)
	}
	go wsClient.Listen()

	address, err := sdk.NewAddressFromRaw("WAFSWQIF2UBLBHOFOYMIQJXZKRSTNONZIM6VYAZT")
	if err != nil {
		panic(err)
	}

	txn, err := sdk.NewTransferTransaction(
		sdk.NewDeadline(time.Hour),
		address,
		[]*sdk.Mosaic{},
		sdk.NewPlainMessage(fmt.Sprintf("hi there %d", rand.Int())),
		sdk.PrivateTest,
	)
	if err != nil {
		panic(err)
	}

	acct, err := sdk.NewAccountFromPrivateKey("b007b006c2178a8819c6b38dd3b49db1c2170483fdfcff21656f071c7541b5a9", sdk.PrivateTest)
	if err != nil {
		panic(err)
	}

	signedTxn, err := acct.Sign(txn)
	if err != nil {
		panic(err)
	}

	var wg sync.WaitGroup
	wg.Add(1)
	err = wsClient.AddUnconfirmedAddedHandlers(address, func(txn sdk.Transaction) bool {
		fmt.Println("FOUND", txn.GetAbstractTransaction().Hash.String())
		if txn.GetAbstractTransaction().Hash.String() == signedTxn.Hash.String() {
			fmt.Println("FOUND HASH IT ON UNCONFIRMED", txn.GetAbstractTransaction().Hash.String())
			wg.Done()
			// ISSUE
			return true
		}
		return false
	})
	if err != nil {
		panic(err)
	}

	client := sdk.NewClient(nil, conf)
	_, err = client.Transaction.Announce(context.Background(), signedTxn)
	fmt.Println("ANNOUNCED", signedTxn.Hash)
	if err != nil {
		panic(err)
	}

	wg.Wait()

        cancel()

Removing Subscribers from Web-socket client

When creating a new subscriber, we use a function that returns the necessary structure.
When registering, we send argument by value, and when deleting, send argument is by reference. This causes a problem when deleting, because the links do not match. We need to consider a mechanism by which we can accurately identify the subscription

Race on WebSocket handlers

Touches every WebSocket subscriber implementation.
All implementations have map of maps. Also, there is lock which defends wrapper map, but underlying maps are not backed by any lock, what causes Race Condition.

WARNING: DATA RACE
Write at 0x00c0000a64b0 by goroutine 74:
  runtime.mapdelete_fast64()
      /usr/local/Cellar/go/1.12/libexec/src/runtime/map_fast64.go:272 +0x0
  github.com/proximax-storage/go-xpx-catapult-sdk/sdk/websocket/subscribers.(*partialAddedImpl).RemoveHandlers()
      /go/pkg/mod/github.com/proximax-storage/[email protected]/sdk/websocket/subscribers/partial_added.go:65 +0x252
  github.com/proximax-storage/go-xpx-catapult-sdk/sdk/websocket/handlers.(*partialAddedHandler).Handle.func1()
      /go/pkg/mod/github.com/proximax-storage/[email protected]/sdk/websocket/handlers/partial_added.go:46 +0x13a

Previous read at 0x00c0000a64b0 by goroutine 84:
  runtime.mapiternext()
      /usr/local/Cellar/go/1.12/libexec/src/runtime/map.go:853 +0x0
  github.com/proximax-storage/go-xpx-catapult-sdk/sdk/websocket/handlers.(*partialAddedHandler).Handle()
      /go/pkg/mod/github.com/proximax-storage/[email protected]/sdk/websocket/handlers/partial_added.go:35 +0x2cd
  github.com/proximax-storage/go-xpx-catapult-sdk/sdk/websocket.(*messageRouter).RouteMessage()
      /go/pkg/mod/github.com/proximax-storage/[email protected]/sdk/websocket/router.go:43 +0x19e

Goroutine 74 (running) created at:
  github.com/proximax-storage/go-xpx-catapult-sdk/sdk/websocket/handlers.(*partialAddedHandler).Handle()
      /go/pkg/mod/github.com/proximax-storage/[email protected]/sdk/websocket/handlers/partial_added.go:37 +0x2bc
  github.com/proximax-storage/go-xpx-catapult-sdk/sdk/websocket.(*messageRouter).RouteMessage()
      /go/pkg/mod/github.com/proximax-storage/[email protected]/sdk/websocket/router.go:43 +0x19e

Goroutine 84 (running) created at:
  github.com/proximax-storage/go-xpx-catapult-sdk/sdk/websocket.(*CatapultWebsocketClientImpl).Listen()
      /go/pkg/mod/github.com/proximax-storage/[email protected]/sdk/websocket/client.go:168 +0x182

CatapultClient.Close() fails consistently due to race condition

Whenever I tried Close(), it always fails with the error below.

panic: close tcp 192.168.20.11:64395->52.221.198.188:3000: use of closed network connection

goroutine 69 [running]:
github.com/proximax-storage/go-xpx-catapult-sdk/sdk/websocket.(*CatapultWebsocketClientImpl).Listen(0xc000388000)
	C:/Users/Tyrone/go/src/github.com/proximax-storage/go-xpx-catapult-sdk/sdk/websocket/client.go:162 +0x24a
created by main.testWS
	C:/Users/Tyrone/go/src/github.com/proximax-storage/csd-test-playground/test_websocket/main.go:56 +0x1a0

My understanding is there is a race condition on Close() and Listen(). Upon Close(), Listen() would immediately run the first case below.

	for {
		select {
		case <-c.ctx.Done():
			if c.conn != nil {
				if err := c.conn.Close(); err != nil {
					panic(err)
				}
				c.conn = nil
			}
			return
		case msg := <-messagesChan:
			go c.messageRouter.RouteMessage(msg)
		}
	}

My code:

	conf, err := sdk.NewConfig([]string{"http://csddev1.xpxsirius.io:3000", "http://csddev2.xpxsirius.io:3000"}, sdk.PrivateTest, sdk.WebsocketReconnectionDefaultTimeout)
	if err != nil {
		panic(err)
	}

	ctx, cancel := context.WithTimeout(context.TODO(), time.Second*30)
	wsClient, err := websocket.NewClient(ctx, conf)
	if err != nil {
		panic(err)
	}
	go wsClient.Listen()

	address, err := sdk.NewAddressFromRaw("WAFSWQIF2UBLBHOFOYMIQJXZKRSTNONZIM6VYAZT")
	if err != nil {
		panic(err)
	}

	txn, err := sdk.NewTransferTransaction(
		sdk.NewDeadline(time.Hour),
		address,
		[]*sdk.Mosaic{},
		sdk.NewPlainMessage(fmt.Sprintf("hi there %d", rand.Int())),
		sdk.PrivateTest,
	)
	if err != nil {
		panic(err)
	}

	acct, err := sdk.NewAccountFromPrivateKey("b007b006c2178a8819c6b38dd3b49db1c2170483fdfcff21656f071c7541b5a9", sdk.PrivateTest)
	if err != nil {
		panic(err)
	}

	signedTxn, err := acct.Sign(txn)
	if err != nil {
		panic(err)
	}

	var wg sync.WaitGroup
	wg.Add(1)
	err = wsClient.AddUnconfirmedAddedHandlers(address, func(txn sdk.Transaction) bool {
		fmt.Println("FOUND", txn.GetAbstractTransaction().Hash.String())
		if txn.GetAbstractTransaction().Hash.String() == signedTxn.Hash.String() {
			fmt.Println("FOUND HASH IT ON UNCONFIRMED", txn.GetAbstractTransaction().Hash.String())
			wg.Done()
		}
		return false
	})
	if err != nil {
		panic(err)
	}

	client := sdk.NewClient(nil, conf)
	_, err = client.Transaction.Announce(context.Background(), signedTxn)
	fmt.Println("ANNOUNCED", signedTxn.Hash)
	if err != nil {
		panic(err)
	}

	wg.Wait()

	wsClient.Close()

My workaround right now is to use context's cancel function. It works most of the time but has a separate issue.

Intermittent issue on CatapultClient.Listen() when closing websocket

Listen() seems to spawn a goroutine for reading websocket messages.

However, when the websocket is closed, the goroutine sometimes fails with this panic error.

panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0xc8 pc=0xa44116]

goroutine 2753 [running]:
github.com/gorilla/websocket.(*Conn).NextReader(0x0, 0xc00000ed28, 0xc000419f40, 0x404de5, 0xc00053e420, 0xc000419f90)
        C:/Users/Tyrone/go/src/github.com/gorilla/websocket/conn.go:936 +0x26
github.com/gorilla/websocket.(*Conn).ReadMessage(0x0, 0xc000419f90, 0xc0003cac00, 0x331, 0x600, 0x0, 0x0)
        C:/Users/Tyrone/go/src/github.com/gorilla/websocket/conn.go:1026 +0x2f
github.com/proximax-storage/go-xpx-catapult-sdk/sdk/websocket.(*CatapultWebsocketClientImpl).Listen.func1(0xc000375900, 0xc00053e420)
        C:/Users/Tyrone/go/src/github.com/proximax-storage/go-xpx-catapult-sdk/sdk/websocket/client.go:132 +0x116
created by github.com/proximax-storage/go-xpx-catapult-sdk/sdk/websocket.(*CatapultWebsocketClientImpl).Listen
        C:/Users/Tyrone/go/src/github.com/proximax-storage/go-xpx-catapult-sdk/sdk/websocket/client.go:127 +0x98

My understanding is due to the setting of conn to nil as shown on the line below.

	for {
		select {
		case <-c.ctx.Done():
			if c.conn != nil {
				if err := c.conn.Close(); err != nil {
					panic(err)
				}
				c.conn = nil
			}
			return
		case msg := <-messagesChan:
			go c.messageRouter.RouteMessage(msg)
		}
	}

Can we remove the c.conn = nil to avoid panic?

For some reason, I can't replicate on a simple code the issue but on the app it always happens. The removal of above fixed my proble.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.