94 lines
2.2 KiB
Go
94 lines
2.2 KiB
Go
|
package extpool
|
||
|
|
||
|
import (
|
||
|
"errors"
|
||
|
"sync"
|
||
|
|
||
|
"github.com/nspcc-dev/neo-go/pkg/core/blockchainer"
|
||
|
"github.com/nspcc-dev/neo-go/pkg/network/payload"
|
||
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||
|
)
|
||
|
|
||
|
// Pool represents pool of extensible payloads.
|
||
|
type Pool struct {
|
||
|
lock sync.RWMutex
|
||
|
verified map[util.Uint256]*payload.Extensible
|
||
|
chain blockchainer.Blockchainer
|
||
|
}
|
||
|
|
||
|
// New returns new payload pool using provided chain.
|
||
|
func New(bc blockchainer.Blockchainer) *Pool {
|
||
|
return &Pool{
|
||
|
verified: make(map[util.Uint256]*payload.Extensible),
|
||
|
chain: bc,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var (
|
||
|
errDisallowedSender = errors.New("disallowed sender")
|
||
|
errInvalidHeight = errors.New("invalid height")
|
||
|
)
|
||
|
|
||
|
// Add adds extensible payload to the pool.
|
||
|
// First return value specifies if payload was new.
|
||
|
// Second one is nil if and only if payload is valid.
|
||
|
func (p *Pool) Add(e *payload.Extensible) (bool, error) {
|
||
|
if ok, err := p.verify(e); err != nil || !ok {
|
||
|
return ok, err
|
||
|
}
|
||
|
|
||
|
p.lock.Lock()
|
||
|
defer p.lock.Unlock()
|
||
|
|
||
|
h := e.Hash()
|
||
|
if _, ok := p.verified[h]; ok {
|
||
|
return false, nil
|
||
|
}
|
||
|
p.verified[h] = e
|
||
|
return true, nil
|
||
|
}
|
||
|
|
||
|
func (p *Pool) verify(e *payload.Extensible) (bool, error) {
|
||
|
if err := p.chain.VerifyWitness(e.Sender, e, &e.Witness, extensibleVerifyMaxGAS); err != nil {
|
||
|
return false, err
|
||
|
}
|
||
|
h := p.chain.BlockHeight()
|
||
|
if h < e.ValidBlockStart || e.ValidBlockEnd <= h {
|
||
|
// We can receive consensus payload for the last or next block
|
||
|
// which leads to unwanted node disconnect.
|
||
|
if e.ValidBlockEnd == h {
|
||
|
return false, nil
|
||
|
}
|
||
|
return false, errInvalidHeight
|
||
|
}
|
||
|
if !p.chain.IsExtensibleAllowed(e.Sender) {
|
||
|
return false, errDisallowedSender
|
||
|
}
|
||
|
return true, nil
|
||
|
}
|
||
|
|
||
|
// Get returns payload by hash.
|
||
|
func (p *Pool) Get(h util.Uint256) *payload.Extensible {
|
||
|
p.lock.RLock()
|
||
|
defer p.lock.RUnlock()
|
||
|
|
||
|
return p.verified[h]
|
||
|
}
|
||
|
|
||
|
const extensibleVerifyMaxGAS = 2000000
|
||
|
|
||
|
// RemoveStale removes invalid payloads after block processing.
|
||
|
func (p *Pool) RemoveStale(index uint32) {
|
||
|
p.lock.Lock()
|
||
|
defer p.lock.Unlock()
|
||
|
for h, e := range p.verified {
|
||
|
if e.ValidBlockEnd <= index || !p.chain.IsExtensibleAllowed(e.Sender) {
|
||
|
delete(p.verified, h)
|
||
|
continue
|
||
|
}
|
||
|
if err := p.chain.VerifyWitness(e.Sender, e, &e.Witness, extensibleVerifyMaxGAS); err != nil {
|
||
|
delete(p.verified, h)
|
||
|
}
|
||
|
}
|
||
|
}
|