mirror of
https://github.com/nspcc-dev/neo-go.git
synced 2024-11-28 19:31:34 +00:00
*: replace go.uber.org/atomic with sync/atomic
Use sync/atomic everywhere and exclude go.uber.org/atomic from go.mod. Close #2626. Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
This commit is contained in:
parent
7ca4ce0f79
commit
dc3d1300dd
24 changed files with 57 additions and 70 deletions
|
@ -14,6 +14,7 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -42,7 +43,6 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
|
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"go.uber.org/atomic"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Keep contract NEFs consistent between runs.
|
// Keep contract NEFs consistent between runs.
|
||||||
|
|
2
go.mod
2
go.mod
|
@ -25,7 +25,6 @@ require (
|
||||||
github.com/twmb/murmur3 v1.1.5
|
github.com/twmb/murmur3 v1.1.5
|
||||||
github.com/urfave/cli v1.22.5
|
github.com/urfave/cli v1.22.5
|
||||||
go.etcd.io/bbolt v1.3.7
|
go.etcd.io/bbolt v1.3.7
|
||||||
go.uber.org/atomic v1.10.0
|
|
||||||
go.uber.org/zap v1.24.0
|
go.uber.org/zap v1.24.0
|
||||||
golang.org/x/crypto v0.12.0
|
golang.org/x/crypto v0.12.0
|
||||||
golang.org/x/term v0.11.0
|
golang.org/x/term v0.11.0
|
||||||
|
@ -64,6 +63,7 @@ require (
|
||||||
github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect
|
github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect
|
||||||
github.com/spaolacci/murmur3 v1.1.0 // indirect
|
github.com/spaolacci/murmur3 v1.1.0 // indirect
|
||||||
github.com/x448/float16 v0.8.4 // indirect
|
github.com/x448/float16 v0.8.4 // indirect
|
||||||
|
go.uber.org/atomic v1.10.0 // indirect
|
||||||
go.uber.org/multierr v1.9.0 // indirect
|
go.uber.org/multierr v1.9.0 // indirect
|
||||||
golang.org/x/exp v0.0.0-20230801115018-d63ba01acd4b // indirect
|
golang.org/x/exp v0.0.0-20230801115018-d63ba01acd4b // indirect
|
||||||
golang.org/x/mod v0.12.0 // indirect
|
golang.org/x/mod v0.12.0 // indirect
|
||||||
|
|
|
@ -18,7 +18,6 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
uatomic "go.uber.org/atomic"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// FakeChain implements the Blockchainer interface, but does not provide real functionality.
|
// FakeChain implements the Blockchainer interface, but does not provide real functionality.
|
||||||
|
@ -26,7 +25,7 @@ type FakeChain struct {
|
||||||
config.Blockchain
|
config.Blockchain
|
||||||
*mempool.Pool
|
*mempool.Pool
|
||||||
blocksCh []chan *block.Block
|
blocksCh []chan *block.Block
|
||||||
Blockheight uint32
|
Blockheight atomic.Uint32
|
||||||
PoolTxF func(*transaction.Transaction) error
|
PoolTxF func(*transaction.Transaction) error
|
||||||
poolTxWithData func(*transaction.Transaction, any, *mempool.Pool) error
|
poolTxWithData func(*transaction.Transaction, any, *mempool.Pool) error
|
||||||
blocks map[util.Uint256]*block.Block
|
blocks map[util.Uint256]*block.Block
|
||||||
|
@ -42,9 +41,9 @@ type FakeChain struct {
|
||||||
|
|
||||||
// FakeStateSync implements the StateSync interface.
|
// FakeStateSync implements the StateSync interface.
|
||||||
type FakeStateSync struct {
|
type FakeStateSync struct {
|
||||||
IsActiveFlag uatomic.Bool
|
IsActiveFlag atomic.Bool
|
||||||
IsInitializedFlag uatomic.Bool
|
IsInitializedFlag atomic.Bool
|
||||||
RequestHeaders uatomic.Bool
|
RequestHeaders atomic.Bool
|
||||||
InitFunc func(h uint32) error
|
InitFunc func(h uint32) error
|
||||||
TraverseFunc func(root util.Uint256, process func(node mpt.Node, nodeBytes []byte) bool) error
|
TraverseFunc func(root util.Uint256, process func(node mpt.Node, nodeBytes []byte) bool) error
|
||||||
AddMPTNodesFunc func(nodes [][]byte) error
|
AddMPTNodesFunc func(nodes [][]byte) error
|
||||||
|
@ -76,7 +75,7 @@ func NewFakeChainWithCustomCfg(protocolCfg func(c *config.Blockchain)) *FakeChai
|
||||||
func (chain *FakeChain) PutBlock(b *block.Block) {
|
func (chain *FakeChain) PutBlock(b *block.Block) {
|
||||||
chain.blocks[b.Hash()] = b
|
chain.blocks[b.Hash()] = b
|
||||||
chain.hdrHashes[b.Index] = b.Hash()
|
chain.hdrHashes[b.Index] = b.Hash()
|
||||||
atomic.StoreUint32(&chain.Blockheight, b.Index)
|
chain.Blockheight.Store(b.Index)
|
||||||
}
|
}
|
||||||
|
|
||||||
// PutHeader implements the Blockchainer interface.
|
// PutHeader implements the Blockchainer interface.
|
||||||
|
@ -185,7 +184,7 @@ func (chain *FakeChain) AddHeaders(...*block.Header) error {
|
||||||
|
|
||||||
// AddBlock implements the Blockchainer interface.
|
// AddBlock implements the Blockchainer interface.
|
||||||
func (chain *FakeChain) AddBlock(block *block.Block) error {
|
func (chain *FakeChain) AddBlock(block *block.Block) error {
|
||||||
if block.Index == atomic.LoadUint32(&chain.Blockheight)+1 {
|
if block.Index == chain.Blockheight.Load()+1 {
|
||||||
chain.PutBlock(block)
|
chain.PutBlock(block)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -193,12 +192,12 @@ func (chain *FakeChain) AddBlock(block *block.Block) error {
|
||||||
|
|
||||||
// BlockHeight implements the Feer interface.
|
// BlockHeight implements the Feer interface.
|
||||||
func (chain *FakeChain) BlockHeight() uint32 {
|
func (chain *FakeChain) BlockHeight() uint32 {
|
||||||
return atomic.LoadUint32(&chain.Blockheight)
|
return chain.Blockheight.Load()
|
||||||
}
|
}
|
||||||
|
|
||||||
// HeaderHeight implements the Blockchainer interface.
|
// HeaderHeight implements the Blockchainer interface.
|
||||||
func (chain *FakeChain) HeaderHeight() uint32 {
|
func (chain *FakeChain) HeaderHeight() uint32 {
|
||||||
return atomic.LoadUint32(&chain.Blockheight)
|
return chain.Blockheight.Load()
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetAppExecResults implements the Blockchainer interface.
|
// GetAppExecResults implements the Blockchainer interface.
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"sort"
|
"sort"
|
||||||
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/nspcc-dev/dbft"
|
"github.com/nspcc-dev/dbft"
|
||||||
|
@ -26,7 +27,6 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm/emit"
|
"github.com/nspcc-dev/neo-go/pkg/vm/emit"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
||||||
"go.uber.org/atomic"
|
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -100,7 +100,7 @@ type service struct {
|
||||||
wallet *wallet.Wallet
|
wallet *wallet.Wallet
|
||||||
// started is a flag set with Start method that runs an event handling
|
// started is a flag set with Start method that runs an event handling
|
||||||
// goroutine.
|
// goroutine.
|
||||||
started *atomic.Bool
|
started atomic.Bool
|
||||||
quit chan struct{}
|
quit chan struct{}
|
||||||
finished chan struct{}
|
finished chan struct{}
|
||||||
// lastTimestamp contains timestamp for the last processed block.
|
// lastTimestamp contains timestamp for the last processed block.
|
||||||
|
@ -155,7 +155,6 @@ func NewService(cfg Config) (Service, error) {
|
||||||
|
|
||||||
transactions: make(chan *transaction.Transaction, 100),
|
transactions: make(chan *transaction.Transaction, 100),
|
||||||
blockEvents: make(chan *coreb.Block, 1),
|
blockEvents: make(chan *coreb.Block, 1),
|
||||||
started: atomic.NewBool(false),
|
|
||||||
quit: make(chan struct{}),
|
quit: make(chan struct{}),
|
||||||
finished: make(chan struct{}),
|
finished: make(chan struct{}),
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,12 +6,12 @@ import (
|
||||||
"math/bits"
|
"math/bits"
|
||||||
"sort"
|
"sort"
|
||||||
"sync"
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
|
|
||||||
"github.com/holiman/uint256"
|
"github.com/holiman/uint256"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/mempoolevent"
|
"github.com/nspcc-dev/neo-go/pkg/core/mempoolevent"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
"go.uber.org/atomic"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"sync"
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/config"
|
"github.com/nspcc-dev/neo-go/pkg/config"
|
||||||
|
@ -18,7 +19,6 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
"go.uber.org/atomic"
|
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -2,9 +2,9 @@ package bqueue
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"sync"
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/block"
|
"github.com/nspcc-dev/neo-go/pkg/core/block"
|
||||||
"go.uber.org/atomic"
|
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ type Queue struct {
|
||||||
checkBlocks chan struct{}
|
checkBlocks chan struct{}
|
||||||
chain Blockqueuer
|
chain Blockqueuer
|
||||||
relayF func(*block.Block)
|
relayF func(*block.Block)
|
||||||
discarded *atomic.Bool
|
discarded atomic.Bool
|
||||||
len int
|
len int
|
||||||
lenUpdateF func(int)
|
lenUpdateF func(int)
|
||||||
}
|
}
|
||||||
|
@ -49,7 +49,6 @@ func New(bc Blockqueuer, log *zap.Logger, relayer func(*block.Block), lenMetrics
|
||||||
checkBlocks: make(chan struct{}, 1),
|
checkBlocks: make(chan struct{}, 1),
|
||||||
chain: bc,
|
chain: bc,
|
||||||
relayF: relayer,
|
relayF: relayer,
|
||||||
discarded: atomic.NewBool(false),
|
|
||||||
lenUpdateF: lenMetricsUpdater,
|
lenUpdateF: lenMetricsUpdater,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,13 +12,12 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/network/payload"
|
"github.com/nspcc-dev/neo-go/pkg/network/payload"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
atomic2 "go.uber.org/atomic"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type fakeTransp struct {
|
type fakeTransp struct {
|
||||||
retFalse int32
|
retFalse atomic.Int32
|
||||||
started atomic2.Bool
|
started atomic.Bool
|
||||||
closed atomic2.Bool
|
closed atomic.Bool
|
||||||
dialCh chan string
|
dialCh chan string
|
||||||
host string
|
host string
|
||||||
port string
|
port string
|
||||||
|
@ -58,7 +57,7 @@ func newFakeTransp(s *Server, addr string) Transporter {
|
||||||
|
|
||||||
func (ft *fakeTransp) Dial(addr string, timeout time.Duration) (AddressablePeer, error) {
|
func (ft *fakeTransp) Dial(addr string, timeout time.Duration) (AddressablePeer, error) {
|
||||||
var ret error
|
var ret error
|
||||||
if atomic.LoadInt32(&ft.retFalse) > 0 {
|
if ft.retFalse.Load() > 0 {
|
||||||
ret = errors.New("smth bad happened")
|
ret = errors.New("smth bad happened")
|
||||||
}
|
}
|
||||||
ft.dialCh <- addr
|
ft.dialCh <- addr
|
||||||
|
@ -174,7 +173,7 @@ func TestDefaultDiscoverer(t *testing.T) {
|
||||||
require.Equal(t, 2, d.PoolCount())
|
require.Equal(t, 2, d.PoolCount())
|
||||||
|
|
||||||
// Now make Dial() fail and wait to see addresses in the bad list.
|
// Now make Dial() fail and wait to see addresses in the bad list.
|
||||||
atomic.StoreInt32(&ts.retFalse, 1)
|
ts.retFalse.Store(1)
|
||||||
assert.Equal(t, len(set1), d.PoolCount())
|
assert.Equal(t, len(set1), d.PoolCount())
|
||||||
set1D := d.UnconnectedPeers()
|
set1D := d.UnconnectedPeers()
|
||||||
sort.Strings(set1D)
|
sort.Strings(set1D)
|
||||||
|
@ -216,7 +215,7 @@ func TestSeedDiscovery(t *testing.T) {
|
||||||
var seeds = []string{"1.1.1.1:10333", "2.2.2.2:10333"}
|
var seeds = []string{"1.1.1.1:10333", "2.2.2.2:10333"}
|
||||||
ts := &fakeTransp{}
|
ts := &fakeTransp{}
|
||||||
ts.dialCh = make(chan string)
|
ts.dialCh = make(chan string)
|
||||||
atomic.StoreInt32(&ts.retFalse, 1) // Fail all dial requests.
|
ts.retFalse.Store(1) // Fail all dial requests.
|
||||||
sort.Strings(seeds)
|
sort.Strings(seeds)
|
||||||
|
|
||||||
d := NewDefaultDiscovery(seeds, time.Second/10, ts)
|
d := NewDefaultDiscovery(seeds, time.Second/10, ts)
|
||||||
|
|
|
@ -13,7 +13,7 @@ import (
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"sync"
|
"sync"
|
||||||
satomic "sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/config"
|
"github.com/nspcc-dev/neo-go/pkg/config"
|
||||||
|
@ -29,7 +29,6 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/network/extpool"
|
"github.com/nspcc-dev/neo-go/pkg/network/extpool"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/network/payload"
|
"github.com/nspcc-dev/neo-go/pkg/network/payload"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
"go.uber.org/atomic"
|
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -112,7 +111,7 @@ type (
|
||||||
services map[string]Service
|
services map[string]Service
|
||||||
extensHandlers map[string]func(*payload.Extensible) error
|
extensHandlers map[string]func(*payload.Extensible) error
|
||||||
txCallback func(*transaction.Transaction)
|
txCallback func(*transaction.Transaction)
|
||||||
txCbList satomic.Value
|
txCbList atomic.Value
|
||||||
|
|
||||||
txInLock sync.RWMutex
|
txInLock sync.RWMutex
|
||||||
txin chan *transaction.Transaction
|
txin chan *transaction.Transaction
|
||||||
|
@ -134,7 +133,7 @@ type (
|
||||||
|
|
||||||
transactions chan *transaction.Transaction
|
transactions chan *transaction.Transaction
|
||||||
|
|
||||||
syncReached *atomic.Bool
|
syncReached atomic.Bool
|
||||||
|
|
||||||
stateSync StateSync
|
stateSync StateSync
|
||||||
|
|
||||||
|
@ -186,7 +185,6 @@ func newServerFromConstructors(config ServerConfig, chain Ledger, stSync StateSy
|
||||||
handshake: make(chan Peer),
|
handshake: make(chan Peer),
|
||||||
txInMap: make(map[util.Uint256]struct{}),
|
txInMap: make(map[util.Uint256]struct{}),
|
||||||
peers: make(map[Peer]bool),
|
peers: make(map[Peer]bool),
|
||||||
syncReached: atomic.NewBool(false),
|
|
||||||
mempool: chain.GetMemPool(),
|
mempool: chain.GetMemPool(),
|
||||||
extensiblePool: extpool.New(chain, config.ExtensiblePoolSize),
|
extensiblePool: extpool.New(chain, config.ExtensiblePoolSize),
|
||||||
log: log,
|
log: log,
|
||||||
|
|
|
@ -7,7 +7,7 @@ import (
|
||||||
"net"
|
"net"
|
||||||
"strconv"
|
"strconv"
|
||||||
"sync"
|
"sync"
|
||||||
atomic2 "sync/atomic"
|
"sync/atomic"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -27,7 +27,6 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
|
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"go.uber.org/atomic"
|
|
||||||
"go.uber.org/zap/zaptest"
|
"go.uber.org/zap/zaptest"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -223,7 +222,7 @@ func testGetBlocksByIndex(t *testing.T, cmd CommandType) {
|
||||||
checkPingRespond(t, 3, 5000, 1+3*payload.MaxHashesCount)
|
checkPingRespond(t, 3, 5000, 1+3*payload.MaxHashesCount)
|
||||||
|
|
||||||
// Receive some blocks.
|
// Receive some blocks.
|
||||||
s.chain.(*fakechain.FakeChain).Blockheight = 2123
|
s.chain.(*fakechain.FakeChain).Blockheight.Store(2123)
|
||||||
|
|
||||||
// Minimum chunk has priority.
|
// Minimum chunk has priority.
|
||||||
checkPingRespond(t, 5, 5000, 2124)
|
checkPingRespond(t, 5, 5000, 2124)
|
||||||
|
@ -399,7 +398,7 @@ func startWithCleanup(t *testing.T, s *Server) {
|
||||||
func TestBlock(t *testing.T) {
|
func TestBlock(t *testing.T) {
|
||||||
s := startTestServer(t)
|
s := startTestServer(t)
|
||||||
|
|
||||||
atomic2.StoreUint32(&s.chain.(*fakechain.FakeChain).Blockheight, 12344)
|
s.chain.(*fakechain.FakeChain).Blockheight.Store(12344)
|
||||||
require.Equal(t, uint32(12344), s.chain.BlockHeight())
|
require.Equal(t, uint32(12344), s.chain.BlockHeight())
|
||||||
|
|
||||||
b := block.New(false)
|
b := block.New(false)
|
||||||
|
@ -414,7 +413,7 @@ func TestConsensus(t *testing.T) {
|
||||||
s.AddConsensusService(cons, cons.OnPayload, cons.OnTransaction)
|
s.AddConsensusService(cons, cons.OnPayload, cons.OnTransaction)
|
||||||
startWithCleanup(t, s)
|
startWithCleanup(t, s)
|
||||||
|
|
||||||
atomic2.StoreUint32(&s.chain.(*fakechain.FakeChain).Blockheight, 4)
|
s.chain.(*fakechain.FakeChain).Blockheight.Store(4)
|
||||||
p := newLocalPeer(t, s)
|
p := newLocalPeer(t, s)
|
||||||
p.handshaked = 1
|
p.handshaked = 1
|
||||||
s.register <- p
|
s.register <- p
|
||||||
|
|
|
@ -7,12 +7,12 @@ import (
|
||||||
"net"
|
"net"
|
||||||
"strconv"
|
"strconv"
|
||||||
"sync"
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/io"
|
"github.com/nspcc-dev/neo-go/pkg/io"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/network/capability"
|
"github.com/nspcc-dev/neo-go/pkg/network/capability"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/network/payload"
|
"github.com/nspcc-dev/neo-go/pkg/network/payload"
|
||||||
"go.uber.org/atomic"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type handShakeStage uint8
|
type handShakeStage uint8
|
||||||
|
@ -494,12 +494,12 @@ func (p *TCPPeer) HandlePong(pong *payload.Ping) error {
|
||||||
// AddGetAddrSent increments internal outstanding getaddr requests counter. Then,
|
// AddGetAddrSent increments internal outstanding getaddr requests counter. Then,
|
||||||
// the peer can only send one addr reply per getaddr request.
|
// the peer can only send one addr reply per getaddr request.
|
||||||
func (p *TCPPeer) AddGetAddrSent() {
|
func (p *TCPPeer) AddGetAddrSent() {
|
||||||
p.getAddrSent.Inc()
|
p.getAddrSent.Add(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CanProcessAddr decrements internal outstanding getaddr requests counter and
|
// CanProcessAddr decrements internal outstanding getaddr requests counter and
|
||||||
// answers whether the addr command from the peer can be safely processed.
|
// answers whether the addr command from the peer can be safely processed.
|
||||||
func (p *TCPPeer) CanProcessAddr() bool {
|
func (p *TCPPeer) CanProcessAddr() bool {
|
||||||
v := p.getAddrSent.Dec()
|
v := p.getAddrSent.Add(-1)
|
||||||
return v >= 0
|
return v >= 0
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package actor
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
|
"sync/atomic"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
|
@ -15,7 +16,6 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"go.uber.org/atomic"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type RPCClient struct {
|
type RPCClient struct {
|
||||||
|
|
|
@ -10,13 +10,13 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"sync"
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
|
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/neorpc"
|
"github.com/nspcc-dev/neo-go/pkg/neorpc"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/rpcclient/invoker"
|
"github.com/nspcc-dev/neo-go/pkg/rpcclient/invoker"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
"go.uber.org/atomic"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -48,7 +48,7 @@ type Client struct {
|
||||||
// during regular Client lifecycle.
|
// during regular Client lifecycle.
|
||||||
cache cache
|
cache cache
|
||||||
|
|
||||||
latestReqID *atomic.Uint64
|
latestReqID atomic.Uint64
|
||||||
// getNextRequestID returns an ID to be used for the subsequent request creation.
|
// getNextRequestID returns an ID to be used for the subsequent request creation.
|
||||||
// It is defined on Client, so that our testing code can override this method
|
// It is defined on Client, so that our testing code can override this method
|
||||||
// for the sake of more predictable request IDs generation behavior.
|
// for the sake of more predictable request IDs generation behavior.
|
||||||
|
@ -126,7 +126,7 @@ func initClient(ctx context.Context, cl *Client, endpoint string, opts Options)
|
||||||
cl.cache = cache{
|
cl.cache = cache{
|
||||||
nativeHashes: make(map[string]util.Uint160),
|
nativeHashes: make(map[string]util.Uint160),
|
||||||
}
|
}
|
||||||
cl.latestReqID = atomic.NewUint64(0)
|
cl.latestReqID = atomic.Uint64{}
|
||||||
cl.getNextRequestID = (cl).getRequestID
|
cl.getNextRequestID = (cl).getRequestID
|
||||||
cl.opts = opts
|
cl.opts = opts
|
||||||
cl.requestF = cl.makeHTTPRequest
|
cl.requestF = cl.makeHTTPRequest
|
||||||
|
@ -135,7 +135,7 @@ func initClient(ctx context.Context, cl *Client, endpoint string, opts Options)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) getRequestID() uint64 {
|
func (c *Client) getRequestID() uint64 {
|
||||||
return c.latestReqID.Inc()
|
return c.latestReqID.Add(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Init sets magic of the network client connected to, stateRootInHeader option
|
// Init sets magic of the network client connected to, stateRootInHeader option
|
||||||
|
|
|
@ -4,7 +4,6 @@ import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/neorpc"
|
"github.com/nspcc-dev/neo-go/pkg/neorpc"
|
||||||
"go.uber.org/atomic"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// InternalHook is a function signature that is required to create a local client
|
// InternalHook is a function signature that is required to create a local client
|
||||||
|
@ -31,7 +30,6 @@ func NewInternal(ctx context.Context, register InternalHook) (*Internal, error)
|
||||||
|
|
||||||
shutdown: make(chan struct{}),
|
shutdown: make(chan struct{}),
|
||||||
done: make(chan struct{}),
|
done: make(chan struct{}),
|
||||||
closeCalled: *atomic.NewBool(false),
|
|
||||||
subscriptions: make(map[string]notificationReceiver),
|
subscriptions: make(map[string]notificationReceiver),
|
||||||
receivers: make(map[any][]string),
|
receivers: make(map[any][]string),
|
||||||
},
|
},
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
"sync"
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
|
@ -16,7 +17,6 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/neorpc"
|
"github.com/nspcc-dev/neo-go/pkg/neorpc"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
|
"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/neorpc/rpcevent"
|
"github.com/nspcc-dev/neo-go/pkg/neorpc/rpcevent"
|
||||||
"go.uber.org/atomic"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// WSClient is a websocket-enabled RPC client that can be used with appropriate
|
// WSClient is a websocket-enabled RPC client that can be used with appropriate
|
||||||
|
@ -426,7 +426,6 @@ func NewWS(ctx context.Context, endpoint string, opts WSOptions) (*WSClient, err
|
||||||
wsOpts: opts,
|
wsOpts: opts,
|
||||||
shutdown: make(chan struct{}),
|
shutdown: make(chan struct{}),
|
||||||
done: make(chan struct{}),
|
done: make(chan struct{}),
|
||||||
closeCalled: *atomic.NewBool(false),
|
|
||||||
respChannels: make(map[uint64]chan *neorpc.Response),
|
respChannels: make(map[uint64]chan *neorpc.Response),
|
||||||
requests: make(chan *neorpc.Request),
|
requests: make(chan *neorpc.Request),
|
||||||
subscriptions: make(map[string]notificationReceiver),
|
subscriptions: make(map[string]notificationReceiver),
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -26,7 +27,6 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm/vmstate"
|
"github.com/nspcc-dev/neo-go/pkg/vm/vmstate"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"go.uber.org/atomic"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestWSClientClose(t *testing.T) {
|
func TestWSClientClose(t *testing.T) {
|
||||||
|
@ -677,23 +677,23 @@ func TestWSConcurrentAccess(t *testing.T) {
|
||||||
wsc, err := NewWS(context.TODO(), httpURLtoWS(srv.URL), WSOptions{})
|
wsc, err := NewWS(context.TODO(), httpURLtoWS(srv.URL), WSOptions{})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
batchCount := 100
|
batchCount := 100
|
||||||
completed := atomic.NewInt32(0)
|
completed := &atomic.Int32{}
|
||||||
for i := 0; i < batchCount; i++ {
|
for i := 0; i < batchCount; i++ {
|
||||||
go func() {
|
go func() {
|
||||||
_, err := wsc.GetBlockCount()
|
_, err := wsc.GetBlockCount()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
completed.Inc()
|
completed.Add(1)
|
||||||
}()
|
}()
|
||||||
go func() {
|
go func() {
|
||||||
_, err := wsc.GetBlockHash(123)
|
_, err := wsc.GetBlockHash(123)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
completed.Inc()
|
completed.Add(1)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
_, err := wsc.GetVersion()
|
_, err := wsc.GetVersion()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
completed.Inc()
|
completed.Add(1)
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
require.Eventually(t, func() bool {
|
require.Eventually(t, func() bool {
|
||||||
|
|
|
@ -6,9 +6,9 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"sync/atomic"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/config"
|
"github.com/nspcc-dev/neo-go/pkg/config"
|
||||||
"go.uber.org/atomic"
|
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ type Service struct {
|
||||||
config config.BasicService
|
config config.BasicService
|
||||||
log *zap.Logger
|
log *zap.Logger
|
||||||
serviceType string
|
serviceType string
|
||||||
started *atomic.Bool
|
started atomic.Bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewService configures logger and returns new service instance.
|
// NewService configures logger and returns new service instance.
|
||||||
|
@ -28,7 +28,6 @@ func NewService(name string, httpServers []*http.Server, cfg config.BasicService
|
||||||
config: cfg,
|
config: cfg,
|
||||||
serviceType: name,
|
serviceType: name,
|
||||||
log: log.With(zap.String("service", name)),
|
log: log.With(zap.String("service", name)),
|
||||||
started: atomic.NewBool(false),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"sync"
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/config"
|
"github.com/nspcc-dev/neo-go/pkg/config"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
|
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
|
||||||
|
@ -23,7 +24,6 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm"
|
"github.com/nspcc-dev/neo-go/pkg/vm"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
|
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
||||||
"go.uber.org/atomic"
|
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -50,7 +50,7 @@ type (
|
||||||
// to be processed in an `onTransaction` callback.
|
// to be processed in an `onTransaction` callback.
|
||||||
newTxs chan txHashPair
|
newTxs chan txHashPair
|
||||||
// started is a status bool to protect from double start/shutdown.
|
// started is a status bool to protect from double start/shutdown.
|
||||||
started *atomic.Bool
|
started atomic.Bool
|
||||||
|
|
||||||
// reqMtx protects requests list.
|
// reqMtx protects requests list.
|
||||||
reqMtx sync.RWMutex
|
reqMtx sync.RWMutex
|
||||||
|
@ -152,7 +152,6 @@ func NewNotary(cfg Config, net netmode.Magic, mp *mempool.Pool, onTransaction fu
|
||||||
requests: make(map[util.Uint256]*request),
|
requests: make(map[util.Uint256]*request),
|
||||||
Config: cfg,
|
Config: cfg,
|
||||||
Network: net,
|
Network: net,
|
||||||
started: atomic.NewBool(false),
|
|
||||||
wallet: wallet,
|
wallet: wallet,
|
||||||
onTransaction: onTransaction,
|
onTransaction: onTransaction,
|
||||||
newTxs: make(chan txHashPair, defaultTxChannelCapacity),
|
newTxs: make(chan txHashPair, defaultTxChannelCapacity),
|
||||||
|
|
|
@ -16,6 +16,7 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
|
@ -56,7 +57,6 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm/emit"
|
"github.com/nspcc-dev/neo-go/pkg/vm/emit"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
|
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||||
"go.uber.org/atomic"
|
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -140,7 +140,7 @@ type (
|
||||||
oracle *atomic.Value
|
oracle *atomic.Value
|
||||||
log *zap.Logger
|
log *zap.Logger
|
||||||
shutdown chan struct{}
|
shutdown chan struct{}
|
||||||
started *atomic.Bool
|
started atomic.Bool
|
||||||
errChan chan<- error
|
errChan chan<- error
|
||||||
|
|
||||||
sessionsLock sync.Mutex
|
sessionsLock sync.Mutex
|
||||||
|
@ -339,7 +339,6 @@ func New(chain Ledger, conf config.RPC, coreServer *network.Server,
|
||||||
log: log,
|
log: log,
|
||||||
oracle: oracleWrapped,
|
oracle: oracleWrapped,
|
||||||
shutdown: make(chan struct{}),
|
shutdown: make(chan struct{}),
|
||||||
started: atomic.NewBool(false),
|
|
||||||
errChan: errChan,
|
errChan: errChan,
|
||||||
|
|
||||||
sessions: make(map[string]*session),
|
sessions: make(map[string]*session),
|
||||||
|
|
|
@ -15,6 +15,7 @@ import (
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync/atomic"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -53,7 +54,6 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"go.uber.org/atomic"
|
|
||||||
"go.uber.org/zap/zapcore"
|
"go.uber.org/zap/zapcore"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
package rpcsrv
|
package rpcsrv
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"sync/atomic"
|
||||||
|
|
||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/neorpc"
|
"github.com/nspcc-dev/neo-go/pkg/neorpc"
|
||||||
"go.uber.org/atomic"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync/atomic"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -15,7 +16,6 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/neorpc"
|
"github.com/nspcc-dev/neo-go/pkg/neorpc"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"go.uber.org/atomic"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const testOverflow = false
|
const testOverflow = false
|
||||||
|
@ -68,7 +68,7 @@ func initCleanServerAndWSClient(t *testing.T) (*core.Blockchain, *Server, *webso
|
||||||
// Use buffered channel to read server's messages and then read expected
|
// Use buffered channel to read server's messages and then read expected
|
||||||
// responses from it.
|
// responses from it.
|
||||||
respMsgs := make(chan []byte, 16)
|
respMsgs := make(chan []byte, 16)
|
||||||
finishedFlag := atomic.NewBool(false)
|
finishedFlag := &atomic.Bool{}
|
||||||
go wsReader(t, ws, respMsgs, finishedFlag)
|
go wsReader(t, ws, respMsgs, finishedFlag)
|
||||||
return chain, rpcSrv, ws, respMsgs, finishedFlag
|
return chain, rpcSrv, ws, respMsgs, finishedFlag
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package stateroot
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"sync"
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/config"
|
"github.com/nspcc-dev/neo-go/pkg/config"
|
||||||
|
@ -14,7 +15,6 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/io"
|
"github.com/nspcc-dev/neo-go/pkg/io"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/network/payload"
|
"github.com/nspcc-dev/neo-go/pkg/network/payload"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
||||||
"go.uber.org/atomic"
|
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -50,7 +50,7 @@ type (
|
||||||
Network netmode.Magic
|
Network netmode.Magic
|
||||||
|
|
||||||
log *zap.Logger
|
log *zap.Logger
|
||||||
started *atomic.Bool
|
started atomic.Bool
|
||||||
accMtx sync.RWMutex
|
accMtx sync.RWMutex
|
||||||
accHeight uint32
|
accHeight uint32
|
||||||
myIndex byte
|
myIndex byte
|
||||||
|
@ -83,7 +83,6 @@ func New(cfg config.StateRoot, sm *stateroot.Module, log *zap.Logger, bc Ledger,
|
||||||
s := &service{
|
s := &service{
|
||||||
Module: sm,
|
Module: sm,
|
||||||
Network: bcConf.Magic,
|
Network: bcConf.Magic,
|
||||||
started: atomic.NewBool(false),
|
|
||||||
chain: bc,
|
chain: bc,
|
||||||
log: log,
|
log: log,
|
||||||
incompleteRoots: make(map[uint32]*incompleteRoot),
|
incompleteRoots: make(map[uint32]*incompleteRoot),
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"crypto/elliptic"
|
"crypto/elliptic"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"sort"
|
"sort"
|
||||||
|
"sync/atomic"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -32,7 +33,6 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"go.uber.org/atomic"
|
|
||||||
"go.uber.org/zap/zaptest"
|
"go.uber.org/zap/zaptest"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue