network: add notary request payload

This commit is contained in:
Anna Shaleva 2020-11-27 13:55:48 +03:00
parent 501c0c93c6
commit 0b5cf78468
24 changed files with 1396 additions and 232 deletions

View file

@ -10,6 +10,7 @@ import (
"github.com/nspcc-dev/neo-go/internal/random"
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
"github.com/nspcc-dev/neo-go/pkg/network/payload"
"github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
"github.com/stretchr/testify/assert"
@ -20,10 +21,9 @@ type FeerStub struct {
feePerByte int64
p2pSigExt bool
blockHeight uint32
balance int64
}
var balance = big.NewInt(10000000)
func (fs *FeerStub) FeePerByte() int64 {
return fs.feePerByte
}
@ -33,7 +33,7 @@ func (fs *FeerStub) BlockHeight() uint32 {
}
func (fs *FeerStub) GetUtilityTokenBalance(uint160 util.Uint160) *big.Int {
return balance
return big.NewInt(fs.balance)
}
func (fs *FeerStub) P2PSigExtensionsEnabled() bool {
@ -41,7 +41,7 @@ func (fs *FeerStub) P2PSigExtensionsEnabled() bool {
}
func testMemPoolAddRemoveWithFeer(t *testing.T, fs Feer) {
mp := New(10)
mp := New(10, 0)
tx := transaction.New(netmode.UnitTestNet, []byte{byte(opcode.PUSH1)}, 0)
tx.Nonce = 0
tx.Signers = []transaction.Signer{{Account: util.Uint160{1, 2, 3}}}
@ -62,7 +62,7 @@ func testMemPoolAddRemoveWithFeer(t *testing.T, fs Feer) {
}
func TestMemPoolRemoveStale(t *testing.T) {
mp := New(5)
mp := New(5, 0)
txs := make([]*transaction.Transaction, 5)
for i := range txs {
txs[i] = transaction.New(netmode.UnitTestNet, []byte{byte(opcode.PUSH1)}, 0)
@ -72,7 +72,7 @@ func TestMemPoolRemoveStale(t *testing.T) {
}
staleTxs := make(chan *transaction.Transaction, 5)
f := func(tx *transaction.Transaction) {
f := func(tx *transaction.Transaction, _ interface{}) {
staleTxs <- tx
}
mp.SetResendThreshold(5, f)
@ -111,9 +111,9 @@ func TestMemPoolAddRemove(t *testing.T) {
}
func TestOverCapacity(t *testing.T) {
var fs = &FeerStub{}
var fs = &FeerStub{balance: 10000000}
const mempoolSize = 10
mp := New(mempoolSize)
mp := New(mempoolSize, 0)
for i := 0; i < mempoolSize; i++ {
tx := transaction.New(netmode.UnitTestNet, []byte{byte(opcode.PUSH1)}, 0)
@ -186,7 +186,7 @@ func TestOverCapacity(t *testing.T) {
func TestGetVerified(t *testing.T) {
var fs = &FeerStub{}
const mempoolSize = 10
mp := New(mempoolSize)
mp := New(mempoolSize, 0)
txes := make([]*transaction.Transaction, 0, mempoolSize)
for i := 0; i < mempoolSize; i++ {
@ -210,7 +210,7 @@ func TestGetVerified(t *testing.T) {
func TestRemoveStale(t *testing.T) {
var fs = &FeerStub{}
const mempoolSize = 10
mp := New(mempoolSize)
mp := New(mempoolSize, 0)
txes1 := make([]*transaction.Transaction, 0, mempoolSize/2)
txes2 := make([]*transaction.Transaction, 0, mempoolSize/2)
@ -243,50 +243,51 @@ func TestRemoveStale(t *testing.T) {
}
func TestMemPoolFees(t *testing.T) {
mp := New(10)
mp := New(10, 0)
fs := &FeerStub{balance: 10000000}
sender0 := util.Uint160{1, 2, 3}
tx0 := transaction.New(netmode.UnitTestNet, []byte{byte(opcode.PUSH1)}, 0)
tx0.NetworkFee = balance.Int64() + 1
tx0.NetworkFee = fs.balance + 1
tx0.Signers = []transaction.Signer{{Account: sender0}}
// insufficient funds to add transaction, and balance shouldn't be stored
require.Equal(t, false, mp.Verify(tx0, &FeerStub{}))
require.Error(t, mp.Add(tx0, &FeerStub{}))
require.Equal(t, false, mp.Verify(tx0, fs))
require.Error(t, mp.Add(tx0, fs))
require.Equal(t, 0, len(mp.fees))
balancePart := new(big.Int).Div(balance, big.NewInt(4))
balancePart := new(big.Int).Div(big.NewInt(fs.balance), big.NewInt(4))
// no problems with adding another transaction with lower fee
tx1 := transaction.New(netmode.UnitTestNet, []byte{byte(opcode.PUSH1)}, 0)
tx1.NetworkFee = balancePart.Int64()
tx1.Signers = []transaction.Signer{{Account: sender0}}
require.NoError(t, mp.Add(tx1, &FeerStub{}))
require.NoError(t, mp.Add(tx1, fs))
require.Equal(t, 1, len(mp.fees))
require.Equal(t, utilityBalanceAndFees{
balance: balance,
balance: big.NewInt(fs.balance),
feeSum: big.NewInt(tx1.NetworkFee),
}, mp.fees[sender0])
// balance shouldn't change after adding one more transaction
tx2 := transaction.New(netmode.UnitTestNet, []byte{byte(opcode.PUSH1)}, 0)
tx2.NetworkFee = new(big.Int).Sub(balance, balancePart).Int64()
tx2.NetworkFee = new(big.Int).Sub(big.NewInt(fs.balance), balancePart).Int64()
tx2.Signers = []transaction.Signer{{Account: sender0}}
require.NoError(t, mp.Add(tx2, &FeerStub{}))
require.NoError(t, mp.Add(tx2, fs))
require.Equal(t, 2, len(mp.verifiedTxes))
require.Equal(t, 1, len(mp.fees))
require.Equal(t, utilityBalanceAndFees{
balance: balance,
feeSum: balance,
balance: big.NewInt(fs.balance),
feeSum: big.NewInt(fs.balance),
}, mp.fees[sender0])
// can't add more transactions as we don't have enough GAS
tx3 := transaction.New(netmode.UnitTestNet, []byte{byte(opcode.PUSH1)}, 0)
tx3.NetworkFee = 1
tx3.Signers = []transaction.Signer{{Account: sender0}}
require.Equal(t, false, mp.Verify(tx3, &FeerStub{}))
require.Error(t, mp.Add(tx3, &FeerStub{}))
require.Equal(t, false, mp.Verify(tx3, fs))
require.Error(t, mp.Add(tx3, fs))
require.Equal(t, 1, len(mp.fees))
require.Equal(t, utilityBalanceAndFees{
balance: balance,
feeSum: balance,
balance: big.NewInt(fs.balance),
feeSum: big.NewInt(fs.balance),
}, mp.fees[sender0])
// check whether sender's fee updates correctly
@ -295,10 +296,10 @@ func TestMemPoolFees(t *testing.T) {
return true
}
return false
}, &FeerStub{})
}, fs)
require.Equal(t, 1, len(mp.fees))
require.Equal(t, utilityBalanceAndFees{
balance: balance,
balance: big.NewInt(fs.balance),
feeSum: big.NewInt(tx2.NetworkFee),
}, mp.fees[sender0])
@ -308,12 +309,13 @@ func TestMemPoolFees(t *testing.T) {
return true
}
return false
}, &FeerStub{})
}, fs)
require.Equal(t, 0, len(mp.fees))
}
func TestMempoolItemsOrder(t *testing.T) {
sender0 := util.Uint160{1, 2, 3}
balance := big.NewInt(10000000)
tx1 := transaction.New(netmode.UnitTestNet, []byte{byte(opcode.PUSH1)}, 0)
tx1.NetworkFee = new(big.Int).Div(balance, big.NewInt(8)).Int64()
@ -352,9 +354,9 @@ func TestMempoolItemsOrder(t *testing.T) {
}
func TestMempoolAddRemoveOracleResponse(t *testing.T) {
mp := New(5)
mp := New(5, 0)
nonce := uint32(0)
fs := &FeerStub{}
fs := &FeerStub{balance: 10000}
newTx := func(netFee int64, id uint64) *transaction.Transaction {
tx := transaction.New(netmode.UnitTestNet, []byte{byte(opcode.PUSH1)}, 0)
tx.NetworkFee = netFee
@ -406,9 +408,9 @@ func TestMempoolAddRemoveOracleResponse(t *testing.T) {
func TestMempoolAddRemoveConflicts(t *testing.T) {
capacity := 6
mp := New(capacity)
mp := New(capacity, 0)
var (
fs = &FeerStub{p2pSigExt: true}
fs = &FeerStub{p2pSigExt: true, balance: 100000}
nonce uint32 = 1
)
getConflictsTx := func(netFee int64, hashes ...util.Uint256) *transaction.Transaction {
@ -524,3 +526,116 @@ func TestMempoolAddRemoveConflicts(t *testing.T) {
require.Equal(t, false, ok)
require.True(t, errors.Is(mp.Add(tx13, fs), ErrConflictsAttribute))
}
func TestMempoolAddWithDataGetData(t *testing.T) {
var (
smallNetFee int64 = 3
nonce uint32
)
fs := &FeerStub{
feePerByte: 0,
p2pSigExt: true,
blockHeight: 5,
balance: 100,
}
mp := New(10, 1)
newTx := func(t *testing.T, netFee int64) *transaction.Transaction {
tx := transaction.New(netmode.UnitTestNet, []byte{byte(opcode.RET)}, 0)
tx.Signers = []transaction.Signer{{}, {}}
tx.NetworkFee = netFee
nonce++
tx.Nonce = nonce
return tx
}
// bad, insufficient deposit
r1 := &payload.P2PNotaryRequest{
MainTransaction: newTx(t, 0),
FallbackTransaction: newTx(t, fs.balance+1),
}
require.True(t, errors.Is(mp.Add(r1.FallbackTransaction, fs, r1), ErrInsufficientFunds))
// good
r2 := &payload.P2PNotaryRequest{
MainTransaction: newTx(t, 0),
FallbackTransaction: newTx(t, smallNetFee),
}
require.NoError(t, mp.Add(r2.FallbackTransaction, fs, r2))
require.True(t, mp.ContainsKey(r2.FallbackTransaction.Hash()))
data, ok := mp.TryGetData(r2.FallbackTransaction.Hash())
require.True(t, ok)
require.Equal(t, r2, data)
// bad, already in pool
require.True(t, errors.Is(mp.Add(r2.FallbackTransaction, fs, r2), ErrDup))
// good, higher priority than r2. The resulting mp.verifiedTxes: [r3, r2]
r3 := &payload.P2PNotaryRequest{
MainTransaction: newTx(t, 0),
FallbackTransaction: newTx(t, smallNetFee+1),
}
require.NoError(t, mp.Add(r3.FallbackTransaction, fs, r3))
require.True(t, mp.ContainsKey(r3.FallbackTransaction.Hash()))
data, ok = mp.TryGetData(r3.FallbackTransaction.Hash())
require.True(t, ok)
require.Equal(t, r3, data)
// good, same priority as r2. The resulting mp.verifiedTxes: [r3, r2, r4]
r4 := &payload.P2PNotaryRequest{
MainTransaction: newTx(t, 0),
FallbackTransaction: newTx(t, smallNetFee),
}
require.NoError(t, mp.Add(r4.FallbackTransaction, fs, r4))
require.True(t, mp.ContainsKey(r4.FallbackTransaction.Hash()))
data, ok = mp.TryGetData(r4.FallbackTransaction.Hash())
require.True(t, ok)
require.Equal(t, r4, data)
// good, same priority as r2. The resulting mp.verifiedTxes: [r3, r2, r4, r5]
r5 := &payload.P2PNotaryRequest{
MainTransaction: newTx(t, 0),
FallbackTransaction: newTx(t, smallNetFee),
}
require.NoError(t, mp.Add(r5.FallbackTransaction, fs, r5))
require.True(t, mp.ContainsKey(r5.FallbackTransaction.Hash()))
data, ok = mp.TryGetData(r5.FallbackTransaction.Hash())
require.True(t, ok)
require.Equal(t, r5, data)
// and both r2's and r4's data should still be reachable
data, ok = mp.TryGetData(r2.FallbackTransaction.Hash())
require.True(t, ok)
require.Equal(t, r2, data)
data, ok = mp.TryGetData(r4.FallbackTransaction.Hash())
require.True(t, ok)
require.Equal(t, r4, data)
// should fail to get unexisting data
_, ok = mp.TryGetData(util.Uint256{0, 0, 0})
require.False(t, ok)
// but getting nil data is OK. The resulting mp.verifiedTxes: [r3, r2, r4, r5, r6]
r6 := newTx(t, smallNetFee)
require.NoError(t, mp.Add(r6, fs, nil))
require.True(t, mp.ContainsKey(r6.Hash()))
data, ok = mp.TryGetData(r6.Hash())
require.True(t, ok)
require.Nil(t, data)
// getting data: item is in verifiedMap, but not in verifiedTxes
r7 := &payload.P2PNotaryRequest{
MainTransaction: newTx(t, 0),
FallbackTransaction: newTx(t, smallNetFee),
}
require.NoError(t, mp.Add(r7.FallbackTransaction, fs, r4))
require.True(t, mp.ContainsKey(r7.FallbackTransaction.Hash()))
r8 := &payload.P2PNotaryRequest{
MainTransaction: newTx(t, 0),
FallbackTransaction: newTx(t, smallNetFee-1),
}
require.NoError(t, mp.Add(r8.FallbackTransaction, fs, r4))
require.True(t, mp.ContainsKey(r8.FallbackTransaction.Hash()))
mp.verifiedTxes = append(mp.verifiedTxes[:len(mp.verifiedTxes)-2], mp.verifiedTxes[len(mp.verifiedTxes)-1])
_, ok = mp.TryGetData(r7.FallbackTransaction.Hash())
require.False(t, ok)
}