network: decouple it from blockchainer.Blockchainer

We don't need all of it.
This commit is contained in:
Roman Khimov 2022-01-14 04:09:54 +03:00
parent ddb23ccf78
commit 746644a4eb
13 changed files with 85 additions and 55 deletions

View file

@ -40,7 +40,7 @@ type FakeChain struct {
MaxVerificationGAS int64
NotaryContractScriptHash util.Uint160
NotaryDepositExpiration uint32
PostBlock []func(blockchainer.Blockchainer, *mempool.Pool, *block.Block)
PostBlock []func(func(*transaction.Transaction, *mempool.Pool, bool) bool, *mempool.Pool, *block.Block)
UtilityTokenBalance *big.Int
}
@ -158,12 +158,12 @@ func (chain *FakeChain) GetMaxVerificationGAS() int64 {
}
// PoolTxWithData implements Blockchainer interface.
func (chain *FakeChain) PoolTxWithData(t *transaction.Transaction, data interface{}, mp *mempool.Pool, feer mempool.Feer, verificationFunction func(bc blockchainer.Blockchainer, t *transaction.Transaction, data interface{}) error) error {
func (chain *FakeChain) PoolTxWithData(t *transaction.Transaction, data interface{}, mp *mempool.Pool, feer mempool.Feer, verificationFunction func(t *transaction.Transaction, data interface{}) error) error {
return chain.poolTxWithData(t, data, mp)
}
// RegisterPostBlock implements Blockchainer interface.
func (chain *FakeChain) RegisterPostBlock(f func(blockchainer.Blockchainer, *mempool.Pool, *block.Block)) {
func (chain *FakeChain) RegisterPostBlock(f func(func(*transaction.Transaction, *mempool.Pool, bool) bool, *mempool.Pool, *block.Block)) {
chain.PostBlock = append(chain.PostBlock, f)
}

View file

@ -150,7 +150,7 @@ type Blockchain struct {
// postBlock is a set of callback methods which should be run under the Blockchain lock after new block is persisted.
// Block's transactions are passed via mempool.
postBlock []func(blockchainer.Blockchainer, *mempool.Pool, *block.Block)
postBlock []func(func(*transaction.Transaction, *mempool.Pool, bool) bool, *mempool.Pool, *block.Block)
sbCommittee keys.PublicKeys
@ -1155,7 +1155,7 @@ func (bc *Blockchain) storeBlock(block *block.Block, txpool *mempool.Pool) error
atomic.StoreUint32(&bc.blockHeight, block.Index)
bc.memPool.RemoveStale(func(tx *transaction.Transaction) bool { return bc.IsTxStillRelevant(tx, txpool, false) }, bc)
for _, f := range bc.postBlock {
f(bc, txpool, block)
f(bc.IsTxStillRelevant, txpool, block)
}
if err := bc.updateExtensibleWhitelist(block.Index); err != nil {
bc.lock.Unlock()
@ -2093,12 +2093,12 @@ func (bc *Blockchain) PoolTx(t *transaction.Transaction, pools ...*mempool.Pool)
}
// PoolTxWithData verifies and tries to add given transaction with additional data into the mempool.
func (bc *Blockchain) PoolTxWithData(t *transaction.Transaction, data interface{}, mp *mempool.Pool, feer mempool.Feer, verificationFunction func(bc blockchainer.Blockchainer, tx *transaction.Transaction, data interface{}) error) error {
func (bc *Blockchain) PoolTxWithData(t *transaction.Transaction, data interface{}, mp *mempool.Pool, feer mempool.Feer, verificationFunction func(tx *transaction.Transaction, data interface{}) error) error {
bc.lock.RLock()
defer bc.lock.RUnlock()
if verificationFunction != nil {
err := verificationFunction(bc, t, data)
err := verificationFunction(t, data)
if err != nil {
return err
}
@ -2330,7 +2330,7 @@ func (bc *Blockchain) P2PSigExtensionsEnabled() bool {
// RegisterPostBlock appends provided function to the list of functions which should be run after new block
// is stored.
func (bc *Blockchain) RegisterPostBlock(f func(blockchainer.Blockchainer, *mempool.Pool, *block.Block)) {
func (bc *Blockchain) RegisterPostBlock(f func(func(*transaction.Transaction, *mempool.Pool, bool) bool, *mempool.Pool, *block.Block)) {
bc.postBlock = append(bc.postBlock, f)
}

View file

@ -16,7 +16,6 @@ import (
"github.com/nspcc-dev/neo-go/pkg/config"
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
"github.com/nspcc-dev/neo-go/pkg/core/block"
"github.com/nspcc-dev/neo-go/pkg/core/blockchainer"
"github.com/nspcc-dev/neo-go/pkg/core/chaindump"
"github.com/nspcc-dev/neo-go/pkg/core/fee"
"github.com/nspcc-dev/neo-go/pkg/core/interop/interopnames"
@ -1073,7 +1072,7 @@ func TestVerifyTx(t *testing.T) {
}
mp := mempool.New(10, 1, false)
verificationF := func(bc blockchainer.Blockchainer, tx *transaction.Transaction, data interface{}) error {
verificationF := func(tx *transaction.Transaction, data interface{}) error {
if data.(int) > 5 {
return errors.New("bad data")
}

View file

@ -21,8 +21,10 @@ import (
// of the blockchain.
type Blockchainer interface {
ApplyPolicyToTxSet([]*transaction.Transaction) []*transaction.Transaction
AddBlock(block *block.Block) error
AddHeaders(...*block.Header) error
BlockHeight() uint32
GetConfig() config.ProtocolConfiguration
Blockqueuer // Blockqueuer interface
CalculateClaimable(h util.Uint160, endHeight uint32) (*big.Int, error)
Close()
InitVerificationContext(ic *interop.Context, hash util.Uint160, witness *transaction.Witness) error
@ -65,8 +67,7 @@ type Blockchainer interface {
mempool.Feer // fee interface
ManagementContractHash() util.Uint160
PoolTx(t *transaction.Transaction, pools ...*mempool.Pool) error
PoolTxWithData(t *transaction.Transaction, data interface{}, mp *mempool.Pool, feer mempool.Feer, verificationFunction func(bc Blockchainer, t *transaction.Transaction, data interface{}) error) error
RegisterPostBlock(f func(Blockchainer, *mempool.Pool, *block.Block))
PoolTxWithData(t *transaction.Transaction, data interface{}, mp *mempool.Pool, feer mempool.Feer, verificationFunction func(t *transaction.Transaction, data interface{}) error) error
SetNotary(mod services.Notary)
SubscribeForBlocks(ch chan<- *block.Block)
SubscribeForExecutions(ch chan<- *state.AppExecResult)

View file

@ -1,10 +0,0 @@
package blockchainer
import "github.com/nspcc-dev/neo-go/pkg/core/block"
// Blockqueuer is an interface for blockqueue.
type Blockqueuer interface {
AddBlock(block *block.Block) error
AddHeaders(...*block.Header) error
BlockHeight() uint32
}

View file

@ -13,7 +13,6 @@ import (
"github.com/nspcc-dev/neo-go/internal/testchain"
"github.com/nspcc-dev/neo-go/pkg/config"
"github.com/nspcc-dev/neo-go/pkg/core/block"
"github.com/nspcc-dev/neo-go/pkg/core/blockchainer"
"github.com/nspcc-dev/neo-go/pkg/core/mempool"
"github.com/nspcc-dev/neo-go/pkg/core/native/noderoles"
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
@ -135,7 +134,7 @@ func TestNotary(t *testing.T) {
require.NoError(t, err)
bc.SetNotary(ntr1)
bc.RegisterPostBlock(func(bc blockchainer.Blockchainer, pool *mempool.Pool, b *block.Block) {
bc.RegisterPostBlock(func(f func(*transaction.Transaction, *mempool.Pool, bool) bool, pool *mempool.Pool, b *block.Block) {
ntr1.PostPersist()
})

View file

@ -4,17 +4,23 @@ import (
"sync"
"github.com/nspcc-dev/neo-go/pkg/core/block"
"github.com/nspcc-dev/neo-go/pkg/core/blockchainer"
"go.uber.org/atomic"
"go.uber.org/zap"
)
// Blockqueuer is the interface for block queue.
type Blockqueuer interface {
AddBlock(block *block.Block) error
AddHeaders(...*block.Header) error
BlockHeight() uint32
}
type blockQueue struct {
log *zap.Logger
queueLock sync.Mutex
queue []*block.Block
checkBlocks chan struct{}
chain blockchainer.Blockqueuer
chain Blockqueuer
relayF func(*block.Block)
discarded *atomic.Bool
len int
@ -26,7 +32,7 @@ const (
blockCacheSize = 2000
)
func newBlockQueue(capacity int, bc blockchainer.Blockqueuer, log *zap.Logger, relayer func(*block.Block)) *blockQueue {
func newBlockQueue(capacity int, bc Blockqueuer, log *zap.Logger, relayer func(*block.Block)) *blockQueue {
if log == nil {
return nil
}

View file

@ -5,11 +5,19 @@ import (
"errors"
"sync"
"github.com/nspcc-dev/neo-go/pkg/core/blockchainer"
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
"github.com/nspcc-dev/neo-go/pkg/network/payload"
"github.com/nspcc-dev/neo-go/pkg/util"
)
// Ledger is enough of Blockchain to satisfy Pool.
type Ledger interface {
BlockHeight() uint32
IsExtensibleAllowed(util.Uint160) bool
VerifyWitness(util.Uint160, hash.Hashable, *transaction.Witness, int64) (int64, error)
}
// Pool represents pool of extensible payloads.
type Pool struct {
lock sync.RWMutex
@ -17,11 +25,11 @@ type Pool struct {
senders map[util.Uint160]*list.List
// singleCap represents maximum number of payloads from the single sender.
singleCap int
chain blockchainer.Blockchainer
chain Ledger
}
// New returns new payload pool using provided chain.
func New(bc blockchainer.Blockchainer, capacity int) *Pool {
func New(bc Ledger, capacity int) *Pool {
if capacity <= 0 {
panic("invalid capacity")
}

View file

@ -4,7 +4,6 @@ import (
"errors"
"testing"
"github.com/nspcc-dev/neo-go/pkg/core/blockchainer"
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
"github.com/nspcc-dev/neo-go/pkg/network/payload"
@ -116,7 +115,7 @@ func (p *Pool) testAdd(t *testing.T, expectedOk bool, expectedErr error, ep *pay
}
type testChain struct {
blockchainer.Blockchainer
Ledger
height uint32
verifyWitness func(util.Uint160) bool
isAllowed func(util.Uint160) bool

View file

@ -3,13 +3,12 @@ package network
import (
"math/big"
"github.com/nspcc-dev/neo-go/pkg/core/blockchainer"
"github.com/nspcc-dev/neo-go/pkg/util"
)
// NotaryFeer implements mempool.Feer interface for Notary balance handling.
type NotaryFeer struct {
bc blockchainer.Blockchainer
bc Ledger
}
// FeePerByte implements mempool.Feer interface.
@ -33,7 +32,7 @@ func (f NotaryFeer) P2PSigExtensionsEnabled() bool {
}
// NewNotaryFeer returns new NotaryFeer instance.
func NewNotaryFeer(bc blockchainer.Blockchainer) NotaryFeer {
func NewNotaryFeer(bc Ledger) NotaryFeer {
return NotaryFeer{
bc: bc,
}

View file

@ -5,6 +5,7 @@ import (
"encoding/binary"
"errors"
"fmt"
"math/big"
mrand "math/rand"
"net"
"sort"
@ -12,9 +13,9 @@ import (
"sync"
"time"
"github.com/nspcc-dev/neo-go/pkg/config"
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
"github.com/nspcc-dev/neo-go/pkg/core/block"
"github.com/nspcc-dev/neo-go/pkg/core/blockchainer"
"github.com/nspcc-dev/neo-go/pkg/core/mempool"
"github.com/nspcc-dev/neo-go/pkg/core/mempoolevent"
"github.com/nspcc-dev/neo-go/pkg/core/mpt"
@ -48,6 +49,31 @@ var (
)
type (
// Ledger is everything Server needs from the blockchain.
Ledger interface {
extpool.Ledger
mempool.Feer
Blockqueuer
GetBlock(hash util.Uint256) (*block.Block, error)
GetConfig() config.ProtocolConfiguration
GetHeader(hash util.Uint256) (*block.Header, error)
GetHeaderHash(int) util.Uint256
GetMaxVerificationGAS() int64
GetMemPool() *mempool.Pool
GetNotaryBalance(acc util.Uint160) *big.Int
GetNotaryContractScriptHash() util.Uint160
GetNotaryDepositExpiration(acc util.Uint160) uint32
GetTransaction(util.Uint256) (*transaction.Transaction, uint32, error)
HasBlock(util.Uint256) bool
HeaderHeight() uint32
P2PSigExtensionsEnabled() bool
PoolTx(t *transaction.Transaction, pools ...*mempool.Pool) error
PoolTxWithData(t *transaction.Transaction, data interface{}, mp *mempool.Pool, feer mempool.Feer, verificationFunction func(t *transaction.Transaction, data interface{}) error) error
RegisterPostBlock(f func(func(*transaction.Transaction, *mempool.Pool, bool) bool, *mempool.Pool, *block.Block))
SubscribeForBlocks(ch chan<- *block.Block)
UnsubscribeFromBlocks(ch chan<- *block.Block)
}
// Service is a service abstraction (oracle, state root, consensus, etc).
Service interface {
Start()
@ -70,7 +96,7 @@ type (
transport Transporter
discovery Discoverer
chain blockchainer.Blockchainer
chain Ledger
bQueue *blockQueue
bSyncQueue *blockQueue
mempool *mempool.Pool
@ -119,13 +145,13 @@ func randomID() uint32 {
}
// NewServer returns a new Server, initialized with the given configuration.
func NewServer(config ServerConfig, chain blockchainer.Blockchainer, stSync StateSync, log *zap.Logger) (*Server, error) {
func NewServer(config ServerConfig, chain Ledger, stSync StateSync, log *zap.Logger) (*Server, error) {
return newServerFromConstructors(config, chain, stSync, log, func(s *Server) Transporter {
return NewTCPTransport(s, net.JoinHostPort(s.ServerConfig.Address, strconv.Itoa(int(s.ServerConfig.Port))), s.log)
}, newDefaultDiscovery)
}
func newServerFromConstructors(config ServerConfig, chain blockchainer.Blockchainer, stSync StateSync, log *zap.Logger,
func newServerFromConstructors(config ServerConfig, chain Ledger, stSync StateSync, log *zap.Logger,
newTransport func(*Server) Transporter,
newDiscovery func([]string, time.Duration, Transporter) Discoverer,
) (*Server, error) {
@ -161,9 +187,9 @@ func newServerFromConstructors(config ServerConfig, chain blockchainer.Blockchai
if chain.P2PSigExtensionsEnabled() {
s.notaryFeer = NewNotaryFeer(chain)
s.notaryRequestPool = mempool.New(chain.GetConfig().P2PNotaryRequestPayloadPoolSize, 1, true)
chain.RegisterPostBlock(func(bc blockchainer.Blockchainer, txpool *mempool.Pool, _ *block.Block) {
chain.RegisterPostBlock(func(isRelevant func(*transaction.Transaction, *mempool.Pool, bool) bool, txpool *mempool.Pool, _ *block.Block) {
s.notaryRequestPool.RemoveStale(func(t *transaction.Transaction) bool {
return bc.IsTxStillRelevant(t, txpool, true)
return isRelevant(t, txpool, true)
}, s.notaryFeer)
})
}
@ -604,7 +630,7 @@ func (s *Server) requestBlocksOrHeaders(p Peer) error {
return nil
}
var (
bq blockchainer.Blockqueuer = s.chain
bq Blockqueuer = s.chain
requestMPTNodes bool
)
if s.stateSync.IsActive() {
@ -974,21 +1000,21 @@ func (s *Server) RelayP2PNotaryRequest(r *payload.P2PNotaryRequest) error {
// verifyAndPoolNotaryRequest verifies NotaryRequest payload and adds it to the payload mempool.
func (s *Server) verifyAndPoolNotaryRequest(r *payload.P2PNotaryRequest) error {
return s.chain.PoolTxWithData(r.FallbackTransaction, r, s.notaryRequestPool, s.notaryFeer, verifyNotaryRequest)
return s.chain.PoolTxWithData(r.FallbackTransaction, r, s.notaryRequestPool, s.notaryFeer, s.verifyNotaryRequest)
}
// verifyNotaryRequest is a function for state-dependant P2PNotaryRequest payload verification which is executed before ordinary blockchain's verification.
func verifyNotaryRequest(bc blockchainer.Blockchainer, _ *transaction.Transaction, data interface{}) error {
func (s *Server) verifyNotaryRequest(_ *transaction.Transaction, data interface{}) error {
r := data.(*payload.P2PNotaryRequest)
payer := r.FallbackTransaction.Signers[1].Account
if _, err := bc.VerifyWitness(payer, r, &r.Witness, bc.GetMaxVerificationGAS()); err != nil {
if _, err := s.chain.VerifyWitness(payer, r, &r.Witness, s.chain.GetMaxVerificationGAS()); err != nil {
return fmt.Errorf("bad P2PNotaryRequest payload witness: %w", err)
}
notaryHash := bc.GetNotaryContractScriptHash()
notaryHash := s.chain.GetNotaryContractScriptHash()
if r.FallbackTransaction.Sender() != notaryHash {
return errors.New("P2PNotary contract should be a sender of the fallback transaction")
}
depositExpiration := bc.GetNotaryDepositExpiration(payer)
depositExpiration := s.chain.GetNotaryDepositExpiration(payer)
if r.FallbackTransaction.ValidUntilBlock >= depositExpiration {
return fmt.Errorf("fallback transaction is valid after deposit is unlocked: ValidUntilBlock is %d, deposit lock expires at %d", r.FallbackTransaction.ValidUntilBlock, depositExpiration)
}
@ -1043,7 +1069,7 @@ func (s *Server) handleGetAddrCmd(p Peer) error {
// 1. Block range is divided into chunks of payload.MaxHashesCount.
// 2. Send requests for chunk in increasing order.
// 3. After all requests were sent, request random height.
func (s *Server) requestBlocks(bq blockchainer.Blockqueuer, p Peer) error {
func (s *Server) requestBlocks(bq Blockqueuer, p Peer) error {
pl := getRequestBlocksPayload(p, bq.BlockHeight(), &s.lastRequestedBlock)
return p.EnqueueP2PMessage(NewMessage(CMDGetBlockByIndex, pl))
}

View file

@ -26,6 +26,7 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.uber.org/atomic"
"go.uber.org/zap/zaptest"
)
type fakeConsensus struct {
@ -1008,6 +1009,9 @@ func TestVerifyNotaryRequest(t *testing.T) {
bc := fakechain.NewFakeChain()
bc.MaxVerificationGAS = 10
bc.NotaryContractScriptHash = util.Uint160{1, 2, 3}
s, err := newServerFromConstructors(ServerConfig{}, bc, new(fakechain.FakeStateSync), zaptest.NewLogger(t), newFakeTransp, newTestDiscovery)
require.NoError(t, err)
t.Cleanup(s.Shutdown)
newNotaryRequest := func() *payload.P2PNotaryRequest {
return &payload.P2PNotaryRequest{
MainTransaction: &transaction.Transaction{Script: []byte{0, 1, 2}},
@ -1021,26 +1025,26 @@ func TestVerifyNotaryRequest(t *testing.T) {
t.Run("bad payload witness", func(t *testing.T) {
bc.VerifyWitnessF = func() (int64, error) { return 0, errors.New("bad witness") }
require.Error(t, verifyNotaryRequest(bc, nil, newNotaryRequest()))
require.Error(t, s.verifyNotaryRequest(nil, newNotaryRequest()))
})
t.Run("bad fallback sender", func(t *testing.T) {
bc.VerifyWitnessF = func() (int64, error) { return 0, nil }
r := newNotaryRequest()
r.FallbackTransaction.Signers[0] = transaction.Signer{Account: util.Uint160{7, 8, 9}}
require.Error(t, verifyNotaryRequest(bc, nil, r))
require.Error(t, s.verifyNotaryRequest(nil, r))
})
t.Run("expired deposit", func(t *testing.T) {
r := newNotaryRequest()
bc.NotaryDepositExpiration = r.FallbackTransaction.ValidUntilBlock
require.Error(t, verifyNotaryRequest(bc, nil, r))
require.Error(t, s.verifyNotaryRequest(nil, r))
})
t.Run("good", func(t *testing.T) {
r := newNotaryRequest()
bc.NotaryDepositExpiration = r.FallbackTransaction.ValidUntilBlock + 1
require.NoError(t, verifyNotaryRequest(bc, nil, r))
require.NoError(t, s.verifyNotaryRequest(nil, r))
})
}

View file

@ -1,7 +1,6 @@
package network
import (
"github.com/nspcc-dev/neo-go/pkg/core/blockchainer"
"github.com/nspcc-dev/neo-go/pkg/core/mpt"
"github.com/nspcc-dev/neo-go/pkg/util"
)
@ -9,7 +8,7 @@ import (
// StateSync represents state sync module.
type StateSync interface {
AddMPTNodes([][]byte) error
blockchainer.Blockqueuer // Blockqueuer interface
Blockqueuer
Init(currChainHeight uint32) error
IsActive() bool
IsInitialized() bool