Merge pull request #601 from nspcc-dev/refactoring/core
core: refactor out Block, BlockBase and Header, closes #597.
This commit is contained in:
commit
32213b1454
36 changed files with 327 additions and 232 deletions
|
@ -8,6 +8,7 @@ import (
|
||||||
|
|
||||||
"github.com/CityOfZion/neo-go/config"
|
"github.com/CityOfZion/neo-go/config"
|
||||||
"github.com/CityOfZion/neo-go/pkg/core"
|
"github.com/CityOfZion/neo-go/pkg/core"
|
||||||
|
"github.com/CityOfZion/neo-go/pkg/core/block"
|
||||||
"github.com/CityOfZion/neo-go/pkg/core/storage"
|
"github.com/CityOfZion/neo-go/pkg/core/storage"
|
||||||
"github.com/CityOfZion/neo-go/pkg/encoding/address"
|
"github.com/CityOfZion/neo-go/pkg/encoding/address"
|
||||||
"github.com/CityOfZion/neo-go/pkg/io"
|
"github.com/CityOfZion/neo-go/pkg/io"
|
||||||
|
@ -268,7 +269,7 @@ func restoreDB(ctx *cli.Context) error {
|
||||||
}
|
}
|
||||||
for ; i < skip+count; i++ {
|
for ; i < skip+count; i++ {
|
||||||
bytes, err := readBlock(reader)
|
bytes, err := readBlock(reader)
|
||||||
block := &core.Block{}
|
block := &block.Block{}
|
||||||
newReader := io.NewBinReaderFromBuf(bytes)
|
newReader := io.NewBinReaderFromBuf(bytes)
|
||||||
block.DecodeBinary(newReader)
|
block.DecodeBinary(newReader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package consensus
|
package consensus
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/CityOfZion/neo-go/pkg/core"
|
coreb "github.com/CityOfZion/neo-go/pkg/core/block"
|
||||||
"github.com/CityOfZion/neo-go/pkg/core/transaction"
|
"github.com/CityOfZion/neo-go/pkg/core/transaction"
|
||||||
"github.com/CityOfZion/neo-go/pkg/util"
|
"github.com/CityOfZion/neo-go/pkg/util"
|
||||||
"github.com/nspcc-dev/dbft/block"
|
"github.com/nspcc-dev/dbft/block"
|
||||||
|
@ -11,7 +11,7 @@ import (
|
||||||
// neoBlock is a wrapper of core.Block which implements
|
// neoBlock is a wrapper of core.Block which implements
|
||||||
// methods necessary for dBFT library.
|
// methods necessary for dBFT library.
|
||||||
type neoBlock struct {
|
type neoBlock struct {
|
||||||
core.Block
|
coreb.Block
|
||||||
|
|
||||||
signature []byte
|
signature []byte
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ var _ block.Block = (*neoBlock)(nil)
|
||||||
|
|
||||||
// Sign implements block.Block interface.
|
// Sign implements block.Block interface.
|
||||||
func (n *neoBlock) Sign(key crypto.PrivateKey) error {
|
func (n *neoBlock) Sign(key crypto.PrivateKey) error {
|
||||||
data := n.BlockBase.GetHashableData()
|
data := n.Base.GetHashableData()
|
||||||
sig, err := key.Sign(data[:])
|
sig, err := key.Sign(data[:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -33,7 +33,7 @@ func (n *neoBlock) Sign(key crypto.PrivateKey) error {
|
||||||
|
|
||||||
// Verify implements block.Block interface.
|
// Verify implements block.Block interface.
|
||||||
func (n *neoBlock) Verify(key crypto.PublicKey, sign []byte) error {
|
func (n *neoBlock) Verify(key crypto.PublicKey, sign []byte) error {
|
||||||
data := n.BlockBase.GetHashableData()
|
data := n.Base.GetHashableData()
|
||||||
return key.Verify(data, sign)
|
return key.Verify(data, sign)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
|
|
||||||
"github.com/CityOfZion/neo-go/config"
|
"github.com/CityOfZion/neo-go/config"
|
||||||
"github.com/CityOfZion/neo-go/pkg/core"
|
"github.com/CityOfZion/neo-go/pkg/core"
|
||||||
|
coreb "github.com/CityOfZion/neo-go/pkg/core/block"
|
||||||
"github.com/CityOfZion/neo-go/pkg/core/transaction"
|
"github.com/CityOfZion/neo-go/pkg/core/transaction"
|
||||||
"github.com/CityOfZion/neo-go/pkg/crypto/hash"
|
"github.com/CityOfZion/neo-go/pkg/crypto/hash"
|
||||||
"github.com/CityOfZion/neo-go/pkg/crypto/keys"
|
"github.com/CityOfZion/neo-go/pkg/crypto/keys"
|
||||||
|
@ -69,7 +70,7 @@ type Config struct {
|
||||||
Broadcast func(p *Payload)
|
Broadcast func(p *Payload)
|
||||||
// RelayBlock is a callback that is called to notify server
|
// RelayBlock is a callback that is called to notify server
|
||||||
// about the new block that needs to be broadcasted.
|
// about the new block that needs to be broadcasted.
|
||||||
RelayBlock func(b *core.Block)
|
RelayBlock func(b *coreb.Block)
|
||||||
// Chain is a core.Blockchainer instance.
|
// Chain is a core.Blockchainer instance.
|
||||||
Chain core.Blockchainer
|
Chain core.Blockchainer
|
||||||
// RequestTx is a callback to which will be called
|
// RequestTx is a callback to which will be called
|
||||||
|
@ -302,7 +303,7 @@ func (s *service) processBlock(b block.Block) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *service) getBlockWitness(b *core.Block) *transaction.Witness {
|
func (s *service) getBlockWitness(b *coreb.Block) *transaction.Witness {
|
||||||
dctx := s.dbft.Context
|
dctx := s.dbft.Context
|
||||||
pubs := convertKeys(dctx.Validators)
|
pubs := convertKeys(dctx.Validators)
|
||||||
sigs := make(map[*keys.PublicKey][]byte)
|
sigs := make(map[*keys.PublicKey][]byte)
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
|
|
||||||
"github.com/CityOfZion/neo-go/config"
|
"github.com/CityOfZion/neo-go/config"
|
||||||
"github.com/CityOfZion/neo-go/pkg/core"
|
"github.com/CityOfZion/neo-go/pkg/core"
|
||||||
|
"github.com/CityOfZion/neo-go/pkg/core/mempool"
|
||||||
"github.com/CityOfZion/neo-go/pkg/core/storage"
|
"github.com/CityOfZion/neo-go/pkg/core/storage"
|
||||||
"github.com/CityOfZion/neo-go/pkg/core/transaction"
|
"github.com/CityOfZion/neo-go/pkg/core/transaction"
|
||||||
"github.com/CityOfZion/neo-go/pkg/crypto/keys"
|
"github.com/CityOfZion/neo-go/pkg/crypto/keys"
|
||||||
|
@ -21,7 +22,7 @@ func TestNewService(t *testing.T) {
|
||||||
Type: transaction.MinerType,
|
Type: transaction.MinerType,
|
||||||
Data: &transaction.MinerTX{Nonce: 12345},
|
Data: &transaction.MinerTX{Nonce: 12345},
|
||||||
}
|
}
|
||||||
item := core.NewPoolItem(tx, new(feer))
|
item := mempool.NewPoolItem(tx, new(feer))
|
||||||
srv.Chain.GetMemPool().TryAdd(tx.Hash(), item)
|
srv.Chain.GetMemPool().TryAdd(tx.Hash(), item)
|
||||||
|
|
||||||
var txx []block.Transaction
|
var txx []block.Transaction
|
||||||
|
@ -39,7 +40,7 @@ func TestService_GetVerified(t *testing.T) {
|
||||||
newMinerTx(4),
|
newMinerTx(4),
|
||||||
}
|
}
|
||||||
pool := srv.Chain.GetMemPool()
|
pool := srv.Chain.GetMemPool()
|
||||||
item := core.NewPoolItem(txs[3], new(feer))
|
item := mempool.NewPoolItem(txs[3], new(feer))
|
||||||
|
|
||||||
require.True(t, pool.TryAdd(txs[3].Hash(), item))
|
require.True(t, pool.TryAdd(txs[3].Hash(), item))
|
||||||
|
|
||||||
|
@ -66,7 +67,7 @@ func TestService_GetVerified(t *testing.T) {
|
||||||
|
|
||||||
t.Run("more than half of the last proposal will be reused", func(t *testing.T) {
|
t.Run("more than half of the last proposal will be reused", func(t *testing.T) {
|
||||||
for _, tx := range txs[:2] {
|
for _, tx := range txs[:2] {
|
||||||
item := core.NewPoolItem(tx, new(feer))
|
item := mempool.NewPoolItem(tx, new(feer))
|
||||||
require.True(t, pool.TryAdd(tx.Hash(), item))
|
require.True(t, pool.TryAdd(tx.Hash(), item))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,7 +116,7 @@ func TestService_getTx(t *testing.T) {
|
||||||
|
|
||||||
require.Equal(t, nil, srv.getTx(h))
|
require.Equal(t, nil, srv.getTx(h))
|
||||||
|
|
||||||
item := core.NewPoolItem(tx, new(feer))
|
item := mempool.NewPoolItem(tx, new(feer))
|
||||||
srv.Chain.GetMemPool().TryAdd(h, item)
|
srv.Chain.GetMemPool().TryAdd(h, item)
|
||||||
|
|
||||||
got := srv.getTx(h)
|
got := srv.getTx(h)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package core
|
package block
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
@ -14,7 +14,7 @@ import (
|
||||||
// Block represents one block in the chain.
|
// Block represents one block in the chain.
|
||||||
type Block struct {
|
type Block struct {
|
||||||
// The base of the block.
|
// The base of the block.
|
||||||
BlockBase
|
Base
|
||||||
|
|
||||||
// Transaction list.
|
// Transaction list.
|
||||||
Transactions []*transaction.Transaction `json:"tx"`
|
Transactions []*transaction.Transaction `json:"tx"`
|
||||||
|
@ -26,7 +26,7 @@ type Block struct {
|
||||||
// Header returns the Header of the Block.
|
// Header returns the Header of the Block.
|
||||||
func (b *Block) Header() *Header {
|
func (b *Block) Header() *Header {
|
||||||
return &Header{
|
return &Header{
|
||||||
BlockBase: b.BlockBase,
|
Base: b.Base,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,8 +39,8 @@ func merkleTreeFromTransactions(txes []*transaction.Transaction) (*hash.MerkleTr
|
||||||
return hash.NewMerkleTree(hashes)
|
return hash.NewMerkleTree(hashes)
|
||||||
}
|
}
|
||||||
|
|
||||||
// rebuildMerkleRoot rebuilds the merkleroot of the block.
|
// RebuildMerkleRoot rebuilds the merkleroot of the block.
|
||||||
func (b *Block) rebuildMerkleRoot() error {
|
func (b *Block) RebuildMerkleRoot() error {
|
||||||
merkle, err := merkleTreeFromTransactions(b.Transactions)
|
merkle, err := merkleTreeFromTransactions(b.Transactions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -126,14 +126,14 @@ func (b *Block) Trim() ([]byte, error) {
|
||||||
// DecodeBinary decodes the block from the given BinReader, implementing
|
// DecodeBinary decodes the block from the given BinReader, implementing
|
||||||
// Serializable interface.
|
// Serializable interface.
|
||||||
func (b *Block) DecodeBinary(br *io.BinReader) {
|
func (b *Block) DecodeBinary(br *io.BinReader) {
|
||||||
b.BlockBase.DecodeBinary(br)
|
b.Base.DecodeBinary(br)
|
||||||
br.ReadArray(&b.Transactions)
|
br.ReadArray(&b.Transactions)
|
||||||
}
|
}
|
||||||
|
|
||||||
// EncodeBinary encodes the block to the given BinWriter, implementing
|
// EncodeBinary encodes the block to the given BinWriter, implementing
|
||||||
// Serializable interface.
|
// Serializable interface.
|
||||||
func (b *Block) EncodeBinary(bw *io.BinWriter) {
|
func (b *Block) EncodeBinary(bw *io.BinWriter) {
|
||||||
b.BlockBase.EncodeBinary(bw)
|
b.Base.EncodeBinary(bw)
|
||||||
bw.WriteArray(b.Transactions)
|
bw.WriteArray(b.Transactions)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package core
|
package block
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
@ -9,8 +9,8 @@ import (
|
||||||
"github.com/CityOfZion/neo-go/pkg/util"
|
"github.com/CityOfZion/neo-go/pkg/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
// BlockBase holds the base info of a block
|
// Base holds the base info of a block
|
||||||
type BlockBase struct {
|
type Base struct {
|
||||||
// Version of the block.
|
// Version of the block.
|
||||||
Version uint32 `json:"version"`
|
Version uint32 `json:"version"`
|
||||||
|
|
||||||
|
@ -47,14 +47,14 @@ type BlockBase struct {
|
||||||
verificationHash util.Uint256
|
verificationHash util.Uint256
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify verifies the integrity of the BlockBase.
|
// Verify verifies the integrity of the Base.
|
||||||
func (b *BlockBase) Verify() bool {
|
func (b *Base) Verify() bool {
|
||||||
// TODO: Need a persisted blockchain for this.
|
// TODO: Need a persisted blockchain for this.
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hash returns the hash of the block.
|
// Hash returns the hash of the block.
|
||||||
func (b *BlockBase) Hash() util.Uint256 {
|
func (b *Base) Hash() util.Uint256 {
|
||||||
if b.hash.Equals(util.Uint256{}) {
|
if b.hash.Equals(util.Uint256{}) {
|
||||||
b.createHash()
|
b.createHash()
|
||||||
}
|
}
|
||||||
|
@ -62,7 +62,7 @@ func (b *BlockBase) Hash() util.Uint256 {
|
||||||
}
|
}
|
||||||
|
|
||||||
// VerificationHash returns the hash of the block used to verify it.
|
// VerificationHash returns the hash of the block used to verify it.
|
||||||
func (b *BlockBase) VerificationHash() util.Uint256 {
|
func (b *Base) VerificationHash() util.Uint256 {
|
||||||
if b.verificationHash.Equals(util.Uint256{}) {
|
if b.verificationHash.Equals(util.Uint256{}) {
|
||||||
b.createHash()
|
b.createHash()
|
||||||
}
|
}
|
||||||
|
@ -70,7 +70,7 @@ func (b *BlockBase) VerificationHash() util.Uint256 {
|
||||||
}
|
}
|
||||||
|
|
||||||
// DecodeBinary implements Serializable interface.
|
// DecodeBinary implements Serializable interface.
|
||||||
func (b *BlockBase) DecodeBinary(br *io.BinReader) {
|
func (b *Base) DecodeBinary(br *io.BinReader) {
|
||||||
b.decodeHashableFields(br)
|
b.decodeHashableFields(br)
|
||||||
|
|
||||||
padding := []byte{0}
|
padding := []byte{0}
|
||||||
|
@ -84,14 +84,14 @@ func (b *BlockBase) DecodeBinary(br *io.BinReader) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// EncodeBinary implements Serializable interface
|
// EncodeBinary implements Serializable interface
|
||||||
func (b *BlockBase) EncodeBinary(bw *io.BinWriter) {
|
func (b *Base) EncodeBinary(bw *io.BinWriter) {
|
||||||
b.encodeHashableFields(bw)
|
b.encodeHashableFields(bw)
|
||||||
bw.WriteBytes([]byte{1})
|
bw.WriteBytes([]byte{1})
|
||||||
b.Script.EncodeBinary(bw)
|
b.Script.EncodeBinary(bw)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetHashableData returns serialized hashable data of the block.
|
// GetHashableData returns serialized hashable data of the block.
|
||||||
func (b *BlockBase) GetHashableData() []byte {
|
func (b *Base) GetHashableData() []byte {
|
||||||
buf := io.NewBufBinWriter()
|
buf := io.NewBufBinWriter()
|
||||||
// No error can occure while encoding hashable fields.
|
// No error can occure while encoding hashable fields.
|
||||||
b.encodeHashableFields(buf.BinWriter)
|
b.encodeHashableFields(buf.BinWriter)
|
||||||
|
@ -105,7 +105,7 @@ func (b *BlockBase) GetHashableData() []byte {
|
||||||
// version, PrevBlock, MerkleRoot, timestamp, and height, the nonce, NextMiner.
|
// version, PrevBlock, MerkleRoot, timestamp, and height, the nonce, NextMiner.
|
||||||
// Since MerkleRoot already contains the hash value of all transactions,
|
// Since MerkleRoot already contains the hash value of all transactions,
|
||||||
// the modification of transaction will influence the hash value of the block.
|
// the modification of transaction will influence the hash value of the block.
|
||||||
func (b *BlockBase) createHash() {
|
func (b *Base) createHash() {
|
||||||
bb := b.GetHashableData()
|
bb := b.GetHashableData()
|
||||||
b.verificationHash = hash.Sha256(bb)
|
b.verificationHash = hash.Sha256(bb)
|
||||||
b.hash = hash.Sha256(b.verificationHash.BytesBE())
|
b.hash = hash.Sha256(b.verificationHash.BytesBE())
|
||||||
|
@ -113,7 +113,7 @@ func (b *BlockBase) createHash() {
|
||||||
|
|
||||||
// encodeHashableFields will only encode the fields used for hashing.
|
// encodeHashableFields will only encode the fields used for hashing.
|
||||||
// see Hash() for more information about the fields.
|
// see Hash() for more information about the fields.
|
||||||
func (b *BlockBase) encodeHashableFields(bw *io.BinWriter) {
|
func (b *Base) encodeHashableFields(bw *io.BinWriter) {
|
||||||
bw.WriteU32LE(b.Version)
|
bw.WriteU32LE(b.Version)
|
||||||
bw.WriteBytes(b.PrevHash[:])
|
bw.WriteBytes(b.PrevHash[:])
|
||||||
bw.WriteBytes(b.MerkleRoot[:])
|
bw.WriteBytes(b.MerkleRoot[:])
|
||||||
|
@ -125,7 +125,7 @@ func (b *BlockBase) encodeHashableFields(bw *io.BinWriter) {
|
||||||
|
|
||||||
// decodeHashableFields decodes the fields used for hashing.
|
// decodeHashableFields decodes the fields used for hashing.
|
||||||
// see Hash() for more information about the fields.
|
// see Hash() for more information about the fields.
|
||||||
func (b *BlockBase) decodeHashableFields(br *io.BinReader) {
|
func (b *Base) decodeHashableFields(br *io.BinReader) {
|
||||||
b.Version = br.ReadU32LE()
|
b.Version = br.ReadU32LE()
|
||||||
br.ReadBytes(b.PrevHash[:])
|
br.ReadBytes(b.PrevHash[:])
|
||||||
br.ReadBytes(b.MerkleRoot[:])
|
br.ReadBytes(b.MerkleRoot[:])
|
|
@ -1,4 +1,4 @@
|
||||||
package core
|
package block
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
|
@ -9,20 +9,17 @@ import (
|
||||||
"github.com/CityOfZion/neo-go/pkg/encoding/address"
|
"github.com/CityOfZion/neo-go/pkg/encoding/address"
|
||||||
"github.com/CityOfZion/neo-go/pkg/io"
|
"github.com/CityOfZion/neo-go/pkg/io"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Test blocks are blocks from mainnet with their corresponding index.
|
// Test blocks are blocks from mainnet with their corresponding index.
|
||||||
|
|
||||||
func TestDecodeBlock1(t *testing.T) {
|
func TestDecodeBlock1(t *testing.T) {
|
||||||
data, err := getBlockData(1)
|
data, err := getBlockData(1)
|
||||||
if err != nil {
|
require.NoError(t, err)
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
b, err := hex.DecodeString(data["raw"].(string))
|
b, err := hex.DecodeString(data["raw"].(string))
|
||||||
if err != nil {
|
require.NoError(t, err)
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
block := &Block{}
|
block := &Block{}
|
||||||
r := io.NewBinReaderFromBuf(b)
|
r := io.NewBinReaderFromBuf(b)
|
||||||
|
@ -51,14 +48,10 @@ func TestTrimmedBlock(t *testing.T) {
|
||||||
block := getDecodedBlock(t, 1)
|
block := getDecodedBlock(t, 1)
|
||||||
|
|
||||||
b, err := block.Trim()
|
b, err := block.Trim()
|
||||||
if err != nil {
|
require.NoError(t, err)
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
trimmedBlock, err := NewBlockFromTrimmedBytes(b)
|
trimmedBlock, err := NewBlockFromTrimmedBytes(b)
|
||||||
if err != nil {
|
require.NoError(t, err)
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
assert.True(t, trimmedBlock.Trimmed)
|
assert.True(t, trimmedBlock.Trimmed)
|
||||||
assert.Equal(t, block.Version, trimmedBlock.Version)
|
assert.Equal(t, block.Version, trimmedBlock.Version)
|
||||||
|
@ -79,7 +72,7 @@ func TestTrimmedBlock(t *testing.T) {
|
||||||
|
|
||||||
func newDumbBlock() *Block {
|
func newDumbBlock() *Block {
|
||||||
return &Block{
|
return &Block{
|
||||||
BlockBase: BlockBase{
|
Base: Base{
|
||||||
Version: 0,
|
Version: 0,
|
||||||
PrevHash: hash.Sha256([]byte("a")),
|
PrevHash: hash.Sha256([]byte("a")),
|
||||||
MerkleRoot: hash.Sha256([]byte("b")),
|
MerkleRoot: hash.Sha256([]byte("b")),
|
||||||
|
@ -108,21 +101,21 @@ func TestHashBlockEqualsHashHeader(t *testing.T) {
|
||||||
func TestBlockVerify(t *testing.T) {
|
func TestBlockVerify(t *testing.T) {
|
||||||
block := newDumbBlock()
|
block := newDumbBlock()
|
||||||
assert.NotNil(t, block.Verify())
|
assert.NotNil(t, block.Verify())
|
||||||
assert.Nil(t, block.rebuildMerkleRoot())
|
assert.Nil(t, block.RebuildMerkleRoot())
|
||||||
assert.Nil(t, block.Verify())
|
assert.Nil(t, block.Verify())
|
||||||
|
|
||||||
block.Transactions = []*transaction.Transaction{
|
block.Transactions = []*transaction.Transaction{
|
||||||
{Type: transaction.IssueType},
|
{Type: transaction.IssueType},
|
||||||
{Type: transaction.MinerType},
|
{Type: transaction.MinerType},
|
||||||
}
|
}
|
||||||
assert.NoError(t, block.rebuildMerkleRoot())
|
assert.NoError(t, block.RebuildMerkleRoot())
|
||||||
assert.NotNil(t, block.Verify())
|
assert.NotNil(t, block.Verify())
|
||||||
|
|
||||||
block.Transactions = []*transaction.Transaction{
|
block.Transactions = []*transaction.Transaction{
|
||||||
{Type: transaction.MinerType},
|
{Type: transaction.MinerType},
|
||||||
{Type: transaction.MinerType},
|
{Type: transaction.MinerType},
|
||||||
}
|
}
|
||||||
assert.NoError(t, block.rebuildMerkleRoot())
|
assert.NoError(t, block.RebuildMerkleRoot())
|
||||||
assert.NotNil(t, block.Verify())
|
assert.NotNil(t, block.Verify())
|
||||||
block.Transactions = []*transaction.Transaction{
|
block.Transactions = []*transaction.Transaction{
|
||||||
{Type: transaction.MinerType},
|
{Type: transaction.MinerType},
|
||||||
|
@ -291,9 +284,9 @@ func TestBlockSizeCalculation(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBlockCompare(t *testing.T) {
|
func TestBlockCompare(t *testing.T) {
|
||||||
b1 := Block{BlockBase: BlockBase{Index: 1}}
|
b1 := Block{Base: Base{Index: 1}}
|
||||||
b2 := Block{BlockBase: BlockBase{Index: 2}}
|
b2 := Block{Base: Base{Index: 2}}
|
||||||
b3 := Block{BlockBase: BlockBase{Index: 3}}
|
b3 := Block{Base: Base{Index: 3}}
|
||||||
assert.Equal(t, 1, b2.Compare(&b1))
|
assert.Equal(t, 1, b2.Compare(&b1))
|
||||||
assert.Equal(t, 0, b2.Compare(&b2))
|
assert.Equal(t, 0, b2.Compare(&b2))
|
||||||
assert.Equal(t, -1, b2.Compare(&b3))
|
assert.Equal(t, -1, b2.Compare(&b3))
|
|
@ -1,4 +1,4 @@
|
||||||
package core
|
package block
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
@ -9,14 +9,14 @@ import (
|
||||||
// Header holds the head info of a block.
|
// Header holds the head info of a block.
|
||||||
type Header struct {
|
type Header struct {
|
||||||
// Base of the block.
|
// Base of the block.
|
||||||
BlockBase
|
Base
|
||||||
// Padding that is fixed to 0.
|
// Padding that is fixed to 0.
|
||||||
_ uint8
|
_ uint8
|
||||||
}
|
}
|
||||||
|
|
||||||
// DecodeBinary implements Serializable interface.
|
// DecodeBinary implements Serializable interface.
|
||||||
func (h *Header) DecodeBinary(r *io.BinReader) {
|
func (h *Header) DecodeBinary(r *io.BinReader) {
|
||||||
h.BlockBase.DecodeBinary(r)
|
h.Base.DecodeBinary(r)
|
||||||
|
|
||||||
padding := []byte{0}
|
padding := []byte{0}
|
||||||
r.ReadBytes(padding)
|
r.ReadBytes(padding)
|
||||||
|
@ -28,6 +28,6 @@ func (h *Header) DecodeBinary(r *io.BinReader) {
|
||||||
|
|
||||||
// EncodeBinary implements Serializable interface.
|
// EncodeBinary implements Serializable interface.
|
||||||
func (h *Header) EncodeBinary(w *io.BinWriter) {
|
func (h *Header) EncodeBinary(w *io.BinWriter) {
|
||||||
h.BlockBase.EncodeBinary(w)
|
h.Base.EncodeBinary(w)
|
||||||
w.WriteBytes([]byte{0})
|
w.WriteBytes([]byte{0})
|
||||||
}
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package core
|
package block
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
@ -12,7 +12,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestHeaderEncodeDecode(t *testing.T) {
|
func TestHeaderEncodeDecode(t *testing.T) {
|
||||||
header := Header{BlockBase: BlockBase{
|
header := Header{Base: Base{
|
||||||
Version: 0,
|
Version: 0,
|
||||||
PrevHash: hash.Sha256([]byte("prevhash")),
|
PrevHash: hash.Sha256([]byte("prevhash")),
|
||||||
MerkleRoot: hash.Sha256([]byte("merkleroot")),
|
MerkleRoot: hash.Sha256([]byte("merkleroot")),
|
39
pkg/core/block/helper_test.go
Normal file
39
pkg/core/block/helper_test.go
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
package block
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/hex"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/CityOfZion/neo-go/pkg/io"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func getDecodedBlock(t *testing.T, i int) *Block {
|
||||||
|
data, err := getBlockData(i)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
b, err := hex.DecodeString(data["raw"].(string))
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
block := &Block{}
|
||||||
|
r := io.NewBinReaderFromBuf(b)
|
||||||
|
block.DecodeBinary(r)
|
||||||
|
require.NoError(t, r.Err)
|
||||||
|
|
||||||
|
return block
|
||||||
|
}
|
||||||
|
|
||||||
|
func getBlockData(i int) (map[string]interface{}, error) {
|
||||||
|
b, err := ioutil.ReadFile(fmt.Sprintf("../test_data/block_%d.json", i))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var data map[string]interface{}
|
||||||
|
if err := json.Unmarshal(b, &data); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return data, err
|
||||||
|
}
|
|
@ -11,6 +11,8 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/CityOfZion/neo-go/config"
|
"github.com/CityOfZion/neo-go/config"
|
||||||
|
"github.com/CityOfZion/neo-go/pkg/core/block"
|
||||||
|
"github.com/CityOfZion/neo-go/pkg/core/mempool"
|
||||||
"github.com/CityOfZion/neo-go/pkg/core/state"
|
"github.com/CityOfZion/neo-go/pkg/core/state"
|
||||||
"github.com/CityOfZion/neo-go/pkg/core/storage"
|
"github.com/CityOfZion/neo-go/pkg/core/storage"
|
||||||
"github.com/CityOfZion/neo-go/pkg/core/transaction"
|
"github.com/CityOfZion/neo-go/pkg/core/transaction"
|
||||||
|
@ -76,7 +78,7 @@ type Blockchain struct {
|
||||||
stopCh chan struct{}
|
stopCh chan struct{}
|
||||||
runToExitCh chan struct{}
|
runToExitCh chan struct{}
|
||||||
|
|
||||||
memPool MemPool
|
memPool mempool.Pool
|
||||||
|
|
||||||
// cache for block verification keys.
|
// cache for block verification keys.
|
||||||
keyCache map[util.Uint160]map[string]*keys.PublicKey
|
keyCache map[util.Uint160]map[string]*keys.PublicKey
|
||||||
|
@ -100,7 +102,7 @@ func NewBlockchain(s storage.Store, cfg config.ProtocolConfiguration, log *zap.L
|
||||||
headersOpDone: make(chan struct{}),
|
headersOpDone: make(chan struct{}),
|
||||||
stopCh: make(chan struct{}),
|
stopCh: make(chan struct{}),
|
||||||
runToExitCh: make(chan struct{}),
|
runToExitCh: make(chan struct{}),
|
||||||
memPool: NewMemPool(50000),
|
memPool: mempool.NewMemPool(50000),
|
||||||
keyCache: make(map[util.Uint160]map[string]*keys.PublicKey),
|
keyCache: make(map[util.Uint160]map[string]*keys.PublicKey),
|
||||||
log: log,
|
log: log,
|
||||||
}
|
}
|
||||||
|
@ -179,7 +181,7 @@ func (bc *Blockchain) init() error {
|
||||||
targetHash = genesisBlock.Hash()
|
targetHash = genesisBlock.Hash()
|
||||||
bc.headerList.Add(targetHash)
|
bc.headerList.Add(targetHash)
|
||||||
}
|
}
|
||||||
headers := make([]*Header, 0)
|
headers := make([]*block.Header, 0)
|
||||||
|
|
||||||
for hash != targetHash {
|
for hash != targetHash {
|
||||||
header, err := bc.GetHeader(hash)
|
header, err := bc.GetHeader(hash)
|
||||||
|
@ -242,7 +244,7 @@ func (bc *Blockchain) Close() {
|
||||||
|
|
||||||
// AddBlock accepts successive block for the Blockchain, verifies it and
|
// AddBlock accepts successive block for the Blockchain, verifies it and
|
||||||
// stores internally. Eventually it will be persisted to the backing storage.
|
// stores internally. Eventually it will be persisted to the backing storage.
|
||||||
func (bc *Blockchain) AddBlock(block *Block) error {
|
func (bc *Blockchain) AddBlock(block *block.Block) error {
|
||||||
expectedHeight := bc.BlockHeight() + 1
|
expectedHeight := bc.BlockHeight() + 1
|
||||||
if expectedHeight != block.Index {
|
if expectedHeight != block.Index {
|
||||||
return fmt.Errorf("expected block %d, but passed block %d", expectedHeight, block.Index)
|
return fmt.Errorf("expected block %d, but passed block %d", expectedHeight, block.Index)
|
||||||
|
@ -276,7 +278,7 @@ func (bc *Blockchain) AddBlock(block *Block) error {
|
||||||
|
|
||||||
// AddHeaders processes the given headers and add them to the
|
// AddHeaders processes the given headers and add them to the
|
||||||
// HeaderHashList.
|
// HeaderHashList.
|
||||||
func (bc *Blockchain) AddHeaders(headers ...*Header) (err error) {
|
func (bc *Blockchain) AddHeaders(headers ...*block.Header) (err error) {
|
||||||
var (
|
var (
|
||||||
start = time.Now()
|
start = time.Now()
|
||||||
batch = bc.dao.store.Batch()
|
batch = bc.dao.store.Batch()
|
||||||
|
@ -321,7 +323,7 @@ func (bc *Blockchain) AddHeaders(headers ...*Header) (err error) {
|
||||||
|
|
||||||
// processHeader processes the given header. Note that this is only thread safe
|
// processHeader processes the given header. Note that this is only thread safe
|
||||||
// if executed in headers operation.
|
// if executed in headers operation.
|
||||||
func (bc *Blockchain) processHeader(h *Header, batch storage.Batch, headerList *HeaderHashList) error {
|
func (bc *Blockchain) processHeader(h *block.Header, batch storage.Batch, headerList *HeaderHashList) error {
|
||||||
headerList.Add(h.Hash())
|
headerList.Add(h.Hash())
|
||||||
|
|
||||||
buf := io.NewBufBinWriter()
|
buf := io.NewBufBinWriter()
|
||||||
|
@ -352,7 +354,7 @@ func (bc *Blockchain) processHeader(h *Header, batch storage.Batch, headerList *
|
||||||
// project. This for the sake of development speed and understanding of what
|
// project. This for the sake of development speed and understanding of what
|
||||||
// is happening here, quite allot as you can see :). If things are wired together
|
// is happening here, quite allot as you can see :). If things are wired together
|
||||||
// and all tests are in place, we can make a more optimized and cleaner implementation.
|
// and all tests are in place, we can make a more optimized and cleaner implementation.
|
||||||
func (bc *Blockchain) storeBlock(block *Block) error {
|
func (bc *Blockchain) storeBlock(block *block.Block) error {
|
||||||
cache := newCachedDao(bc.dao.store)
|
cache := newCachedDao(bc.dao.store)
|
||||||
if err := cache.StoreAsBlock(block, 0); err != nil {
|
if err := cache.StoreAsBlock(block, 0); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -756,10 +758,10 @@ func (bc *Blockchain) GetStorageItems(hash util.Uint160) (map[string]*state.Stor
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetBlock returns a Block by the given hash.
|
// GetBlock returns a Block by the given hash.
|
||||||
func (bc *Blockchain) GetBlock(hash util.Uint256) (*Block, error) {
|
func (bc *Blockchain) GetBlock(hash util.Uint256) (*block.Block, error) {
|
||||||
topBlock := bc.topBlock.Load()
|
topBlock := bc.topBlock.Load()
|
||||||
if topBlock != nil {
|
if topBlock != nil {
|
||||||
if tb, ok := topBlock.(*Block); ok && tb.Hash().Equals(hash) {
|
if tb, ok := topBlock.(*block.Block); ok && tb.Hash().Equals(hash) {
|
||||||
return tb, nil
|
return tb, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -782,10 +784,10 @@ func (bc *Blockchain) GetBlock(hash util.Uint256) (*Block, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetHeader returns data block header identified with the given hash value.
|
// GetHeader returns data block header identified with the given hash value.
|
||||||
func (bc *Blockchain) GetHeader(hash util.Uint256) (*Header, error) {
|
func (bc *Blockchain) GetHeader(hash util.Uint256) (*block.Header, error) {
|
||||||
topBlock := bc.topBlock.Load()
|
topBlock := bc.topBlock.Load()
|
||||||
if topBlock != nil {
|
if topBlock != nil {
|
||||||
if tb, ok := topBlock.(*Block); ok && tb.Hash().Equals(hash) {
|
if tb, ok := topBlock.(*block.Block); ok && tb.Hash().Equals(hash) {
|
||||||
return tb.Header(), nil
|
return tb.Header(), nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -950,12 +952,12 @@ func (bc *Blockchain) IsLowPriority(t *transaction.Transaction) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetMemPool returns the memory pool of the blockchain.
|
// GetMemPool returns the memory pool of the blockchain.
|
||||||
func (bc *Blockchain) GetMemPool() MemPool {
|
func (bc *Blockchain) GetMemPool() mempool.Pool {
|
||||||
return bc.memPool
|
return bc.memPool
|
||||||
}
|
}
|
||||||
|
|
||||||
// VerifyBlock verifies block against its current state.
|
// VerifyBlock verifies block against its current state.
|
||||||
func (bc *Blockchain) VerifyBlock(block *Block) error {
|
func (bc *Blockchain) VerifyBlock(block *block.Block) error {
|
||||||
prevHeader, err := bc.GetHeader(block.PrevHash)
|
prevHeader, err := bc.GetHeader(block.PrevHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "unable to get previous header")
|
return errors.Wrap(err, "unable to get previous header")
|
||||||
|
@ -973,7 +975,7 @@ func (bc *Blockchain) VerifyBlock(block *Block) error {
|
||||||
// is used for easy interop access and can be omitted for transactions that are
|
// is used for easy interop access and can be omitted for transactions that are
|
||||||
// not yet added into any block.
|
// not yet added into any block.
|
||||||
// Golang implementation of Verify method in C# (https://github.com/neo-project/neo/blob/master/neo/Network/P2P/Payloads/Transaction.cs#L270).
|
// Golang implementation of Verify method in C# (https://github.com/neo-project/neo/blob/master/neo/Network/P2P/Payloads/Transaction.cs#L270).
|
||||||
func (bc *Blockchain) VerifyTx(t *transaction.Transaction, block *Block) error {
|
func (bc *Blockchain) VerifyTx(t *transaction.Transaction, block *block.Block) error {
|
||||||
if io.GetVarSize(t) > transaction.MaxTransactionSize {
|
if io.GetVarSize(t) > transaction.MaxTransactionSize {
|
||||||
return errors.Errorf("invalid transaction size = %d. It shoud be less then MaxTransactionSize = %d", io.GetVarSize(t), transaction.MaxTransactionSize)
|
return errors.Errorf("invalid transaction size = %d. It shoud be less then MaxTransactionSize = %d", io.GetVarSize(t), transaction.MaxTransactionSize)
|
||||||
}
|
}
|
||||||
|
@ -1440,7 +1442,7 @@ func (bc *Blockchain) verifyHashAgainstScript(hash util.Uint160, witness *transa
|
||||||
// not yet added into any block.
|
// not yet added into any block.
|
||||||
// Golang implementation of VerifyWitnesses method in C# (https://github.com/neo-project/neo/blob/master/neo/SmartContract/Helper.cs#L87).
|
// Golang implementation of VerifyWitnesses method in C# (https://github.com/neo-project/neo/blob/master/neo/SmartContract/Helper.cs#L87).
|
||||||
// Unfortunately the IVerifiable interface could not be implemented because we can't move the References method in blockchain.go to the transaction.go file.
|
// Unfortunately the IVerifiable interface could not be implemented because we can't move the References method in blockchain.go to the transaction.go file.
|
||||||
func (bc *Blockchain) verifyTxWitnesses(t *transaction.Transaction, block *Block) error {
|
func (bc *Blockchain) verifyTxWitnesses(t *transaction.Transaction, block *block.Block) error {
|
||||||
hashes, err := bc.GetScriptHashesForVerifying(t)
|
hashes, err := bc.GetScriptHashesForVerifying(t)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -1465,7 +1467,7 @@ func (bc *Blockchain) verifyTxWitnesses(t *transaction.Transaction, block *Block
|
||||||
}
|
}
|
||||||
|
|
||||||
// verifyBlockWitnesses is a block-specific implementation of VerifyWitnesses logic.
|
// verifyBlockWitnesses is a block-specific implementation of VerifyWitnesses logic.
|
||||||
func (bc *Blockchain) verifyBlockWitnesses(block *Block, prevHeader *Header) error {
|
func (bc *Blockchain) verifyBlockWitnesses(block *block.Block, prevHeader *block.Header) error {
|
||||||
var hash util.Uint160
|
var hash util.Uint160
|
||||||
if prevHeader == nil && block.PrevHash.Equals(util.Uint256{}) {
|
if prevHeader == nil && block.PrevHash.Equals(util.Uint256{}) {
|
||||||
hash = block.Script.ScriptHash()
|
hash = block.Script.ScriptHash()
|
||||||
|
@ -1487,6 +1489,6 @@ func (bc *Blockchain) secondsPerBlock() int {
|
||||||
return bc.config.SecondsPerBlock
|
return bc.config.SecondsPerBlock
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bc *Blockchain) newInteropContext(trigger byte, s storage.Store, block *Block, tx *transaction.Transaction) *interopContext {
|
func (bc *Blockchain) newInteropContext(trigger byte, s storage.Store, block *block.Block, tx *transaction.Transaction) *interopContext {
|
||||||
return newInteropContext(trigger, bc, s, block, tx, bc.log)
|
return newInteropContext(trigger, bc, s, block, tx, bc.log)
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package core
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/CityOfZion/neo-go/pkg/core/block"
|
||||||
"github.com/CityOfZion/neo-go/pkg/core/storage"
|
"github.com/CityOfZion/neo-go/pkg/core/storage"
|
||||||
"github.com/CityOfZion/neo-go/pkg/core/transaction"
|
"github.com/CityOfZion/neo-go/pkg/core/transaction"
|
||||||
"github.com/CityOfZion/neo-go/pkg/crypto/hash"
|
"github.com/CityOfZion/neo-go/pkg/crypto/hash"
|
||||||
|
@ -38,7 +39,7 @@ func TestAddHeaders(t *testing.T) {
|
||||||
|
|
||||||
func TestAddBlock(t *testing.T) {
|
func TestAddBlock(t *testing.T) {
|
||||||
bc := newTestChain(t)
|
bc := newTestChain(t)
|
||||||
blocks := []*Block{
|
blocks := []*block.Block{
|
||||||
newBlock(1, newMinerTX()),
|
newBlock(1, newMinerTX()),
|
||||||
newBlock(2, newMinerTX()),
|
newBlock(2, newMinerTX()),
|
||||||
newBlock(3, newMinerTX()),
|
newBlock(3, newMinerTX()),
|
||||||
|
|
|
@ -2,6 +2,8 @@ package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/CityOfZion/neo-go/config"
|
"github.com/CityOfZion/neo-go/config"
|
||||||
|
"github.com/CityOfZion/neo-go/pkg/core/block"
|
||||||
|
"github.com/CityOfZion/neo-go/pkg/core/mempool"
|
||||||
"github.com/CityOfZion/neo-go/pkg/core/state"
|
"github.com/CityOfZion/neo-go/pkg/core/state"
|
||||||
"github.com/CityOfZion/neo-go/pkg/core/storage"
|
"github.com/CityOfZion/neo-go/pkg/core/storage"
|
||||||
"github.com/CityOfZion/neo-go/pkg/core/transaction"
|
"github.com/CityOfZion/neo-go/pkg/core/transaction"
|
||||||
|
@ -14,15 +16,15 @@ import (
|
||||||
// of the blockchain.
|
// of the blockchain.
|
||||||
type Blockchainer interface {
|
type Blockchainer interface {
|
||||||
GetConfig() config.ProtocolConfiguration
|
GetConfig() config.ProtocolConfiguration
|
||||||
AddHeaders(...*Header) error
|
AddHeaders(...*block.Header) error
|
||||||
AddBlock(*Block) error
|
AddBlock(*block.Block) error
|
||||||
BlockHeight() uint32
|
BlockHeight() uint32
|
||||||
Close()
|
Close()
|
||||||
HeaderHeight() uint32
|
HeaderHeight() uint32
|
||||||
GetBlock(hash util.Uint256) (*Block, error)
|
GetBlock(hash util.Uint256) (*block.Block, error)
|
||||||
GetContractState(hash util.Uint160) *state.Contract
|
GetContractState(hash util.Uint160) *state.Contract
|
||||||
GetHeaderHash(int) util.Uint256
|
GetHeaderHash(int) util.Uint256
|
||||||
GetHeader(hash util.Uint256) (*Header, error)
|
GetHeader(hash util.Uint256) (*block.Header, error)
|
||||||
CurrentHeaderHash() util.Uint256
|
CurrentHeaderHash() util.Uint256
|
||||||
CurrentBlockHash() util.Uint256
|
CurrentBlockHash() util.Uint256
|
||||||
HasBlock(util.Uint256) bool
|
HasBlock(util.Uint256) bool
|
||||||
|
@ -37,7 +39,7 @@ type Blockchainer interface {
|
||||||
GetTransaction(util.Uint256) (*transaction.Transaction, uint32, error)
|
GetTransaction(util.Uint256) (*transaction.Transaction, uint32, error)
|
||||||
GetUnspentCoinState(util.Uint256) *UnspentCoinState
|
GetUnspentCoinState(util.Uint256) *UnspentCoinState
|
||||||
References(t *transaction.Transaction) map[transaction.Input]*transaction.Output
|
References(t *transaction.Transaction) map[transaction.Input]*transaction.Output
|
||||||
Feer // fee interface
|
mempool.Feer // fee interface
|
||||||
VerifyTx(*transaction.Transaction, *Block) error
|
VerifyTx(*transaction.Transaction, *block.Block) error
|
||||||
GetMemPool() MemPool
|
GetMemPool() mempool.Pool
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
|
"github.com/CityOfZion/neo-go/pkg/core/block"
|
||||||
"github.com/CityOfZion/neo-go/pkg/core/state"
|
"github.com/CityOfZion/neo-go/pkg/core/state"
|
||||||
"github.com/CityOfZion/neo-go/pkg/core/storage"
|
"github.com/CityOfZion/neo-go/pkg/core/storage"
|
||||||
"github.com/CityOfZion/neo-go/pkg/core/transaction"
|
"github.com/CityOfZion/neo-go/pkg/core/transaction"
|
||||||
|
@ -358,13 +359,13 @@ func makeStorageItemKey(scripthash util.Uint160, key []byte) []byte {
|
||||||
// -- other.
|
// -- other.
|
||||||
|
|
||||||
// GetBlock returns Block by the given hash if it exists in the store.
|
// GetBlock returns Block by the given hash if it exists in the store.
|
||||||
func (dao *dao) GetBlock(hash util.Uint256) (*Block, error) {
|
func (dao *dao) GetBlock(hash util.Uint256) (*block.Block, error) {
|
||||||
key := storage.AppendPrefix(storage.DataBlock, hash.BytesLE())
|
key := storage.AppendPrefix(storage.DataBlock, hash.BytesLE())
|
||||||
b, err := dao.store.Get(key)
|
b, err := dao.store.Get(key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
block, err := NewBlockFromTrimmedBytes(b)
|
block, err := block.NewBlockFromTrimmedBytes(b)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -486,7 +487,7 @@ func (dao *dao) HasTransaction(hash util.Uint256) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// StoreAsBlock stores the given block as DataBlock.
|
// StoreAsBlock stores the given block as DataBlock.
|
||||||
func (dao *dao) StoreAsBlock(block *Block, sysFee uint32) error {
|
func (dao *dao) StoreAsBlock(block *block.Block, sysFee uint32) error {
|
||||||
var (
|
var (
|
||||||
key = storage.AppendPrefix(storage.DataBlock, block.Hash().BytesLE())
|
key = storage.AppendPrefix(storage.DataBlock, block.Hash().BytesLE())
|
||||||
buf = io.NewBufBinWriter()
|
buf = io.NewBufBinWriter()
|
||||||
|
@ -505,7 +506,7 @@ func (dao *dao) StoreAsBlock(block *Block, sysFee uint32) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// StoreAsCurrentBlock stores the given block witch prefix SYSCurrentBlock.
|
// StoreAsCurrentBlock stores the given block witch prefix SYSCurrentBlock.
|
||||||
func (dao *dao) StoreAsCurrentBlock(block *Block) error {
|
func (dao *dao) StoreAsCurrentBlock(block *block.Block) error {
|
||||||
buf := io.NewBufBinWriter()
|
buf := io.NewBufBinWriter()
|
||||||
h := block.Hash()
|
h := block.Hash()
|
||||||
h.EncodeBinary(buf.BinWriter)
|
h.EncodeBinary(buf.BinWriter)
|
||||||
|
|
|
@ -3,6 +3,7 @@ package core
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/CityOfZion/neo-go/pkg/core/block"
|
||||||
"github.com/CityOfZion/neo-go/pkg/core/state"
|
"github.com/CityOfZion/neo-go/pkg/core/state"
|
||||||
"github.com/CityOfZion/neo-go/pkg/core/storage"
|
"github.com/CityOfZion/neo-go/pkg/core/storage"
|
||||||
"github.com/CityOfZion/neo-go/pkg/core/transaction"
|
"github.com/CityOfZion/neo-go/pkg/core/transaction"
|
||||||
|
@ -260,16 +261,16 @@ func TestGetBlock_NotExists(t *testing.T) {
|
||||||
|
|
||||||
func TestPutGetBlock(t *testing.T) {
|
func TestPutGetBlock(t *testing.T) {
|
||||||
dao := newDao(storage.NewMemoryStore())
|
dao := newDao(storage.NewMemoryStore())
|
||||||
block := &Block{
|
b := &block.Block{
|
||||||
BlockBase: BlockBase{
|
Base: block.Base{
|
||||||
Script: transaction.Witness{
|
Script: transaction.Witness{
|
||||||
VerificationScript: []byte{byte(opcode.PUSH1)},
|
VerificationScript: []byte{byte(opcode.PUSH1)},
|
||||||
InvocationScript: []byte{byte(opcode.NOP)},
|
InvocationScript: []byte{byte(opcode.NOP)},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
hash := block.Hash()
|
hash := b.Hash()
|
||||||
err := dao.StoreAsBlock(block, 0)
|
err := dao.StoreAsBlock(b, 0)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
gotBlock, err := dao.GetBlock(hash)
|
gotBlock, err := dao.GetBlock(hash)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -301,15 +302,15 @@ func TestGetCurrentHeaderHeight_NoHeader(t *testing.T) {
|
||||||
|
|
||||||
func TestGetCurrentHeaderHeight_Store(t *testing.T) {
|
func TestGetCurrentHeaderHeight_Store(t *testing.T) {
|
||||||
dao := newDao(storage.NewMemoryStore())
|
dao := newDao(storage.NewMemoryStore())
|
||||||
block := &Block{
|
b := &block.Block{
|
||||||
BlockBase: BlockBase{
|
Base: block.Base{
|
||||||
Script: transaction.Witness{
|
Script: transaction.Witness{
|
||||||
VerificationScript: []byte{byte(opcode.PUSH1)},
|
VerificationScript: []byte{byte(opcode.PUSH1)},
|
||||||
InvocationScript: []byte{byte(opcode.NOP)},
|
InvocationScript: []byte{byte(opcode.NOP)},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
err := dao.StoreAsCurrentBlock(block)
|
err := dao.StoreAsCurrentBlock(b)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
height, err := dao.GetCurrentBlockHeight()
|
height, err := dao.GetCurrentBlockHeight()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
|
@ -9,8 +9,10 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/CityOfZion/neo-go/config"
|
"github.com/CityOfZion/neo-go/config"
|
||||||
|
"github.com/CityOfZion/neo-go/pkg/core/block"
|
||||||
"github.com/CityOfZion/neo-go/pkg/core/storage"
|
"github.com/CityOfZion/neo-go/pkg/core/storage"
|
||||||
"github.com/CityOfZion/neo-go/pkg/core/transaction"
|
"github.com/CityOfZion/neo-go/pkg/core/transaction"
|
||||||
|
"github.com/CityOfZion/neo-go/pkg/crypto/hash"
|
||||||
"github.com/CityOfZion/neo-go/pkg/crypto/keys"
|
"github.com/CityOfZion/neo-go/pkg/crypto/keys"
|
||||||
"github.com/CityOfZion/neo-go/pkg/io"
|
"github.com/CityOfZion/neo-go/pkg/io"
|
||||||
"github.com/CityOfZion/neo-go/pkg/smartcontract"
|
"github.com/CityOfZion/neo-go/pkg/smartcontract"
|
||||||
|
@ -49,7 +51,7 @@ func newTestChain(t *testing.T) *Blockchain {
|
||||||
return chain
|
return chain
|
||||||
}
|
}
|
||||||
|
|
||||||
func newBlock(index uint32, txs ...*transaction.Transaction) *Block {
|
func newBlock(index uint32, txs ...*transaction.Transaction) *block.Block {
|
||||||
validators, _ := getValidators(unitTestNetCfg.ProtocolConfiguration)
|
validators, _ := getValidators(unitTestNetCfg.ProtocolConfiguration)
|
||||||
vlen := len(validators)
|
vlen := len(validators)
|
||||||
valScript, _ := smartcontract.CreateMultiSigRedeemScript(
|
valScript, _ := smartcontract.CreateMultiSigRedeemScript(
|
||||||
|
@ -59,8 +61,8 @@ func newBlock(index uint32, txs ...*transaction.Transaction) *Block {
|
||||||
witness := transaction.Witness{
|
witness := transaction.Witness{
|
||||||
VerificationScript: valScript,
|
VerificationScript: valScript,
|
||||||
}
|
}
|
||||||
b := &Block{
|
b := &block.Block{
|
||||||
BlockBase: BlockBase{
|
Base: block.Base{
|
||||||
Version: 0,
|
Version: 0,
|
||||||
PrevHash: newBlockPrevHash,
|
PrevHash: newBlockPrevHash,
|
||||||
Timestamp: uint32(time.Now().UTC().Unix()) + index,
|
Timestamp: uint32(time.Now().UTC().Unix()) + index,
|
||||||
|
@ -71,8 +73,7 @@ func newBlock(index uint32, txs ...*transaction.Transaction) *Block {
|
||||||
},
|
},
|
||||||
Transactions: txs,
|
Transactions: txs,
|
||||||
}
|
}
|
||||||
_ = b.rebuildMerkleRoot()
|
_ = b.RebuildMerkleRoot()
|
||||||
b.createHash()
|
|
||||||
newBlockPrevHash = b.Hash()
|
newBlockPrevHash = b.Hash()
|
||||||
|
|
||||||
invScript := make([]byte, 0)
|
invScript := make([]byte, 0)
|
||||||
|
@ -93,8 +94,8 @@ func newBlock(index uint32, txs ...*transaction.Transaction) *Block {
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeBlocks(n int) []*Block {
|
func makeBlocks(n int) []*block.Block {
|
||||||
blocks := make([]*Block, n)
|
blocks := make([]*block.Block, n)
|
||||||
for i := 0; i < n; i++ {
|
for i := 0; i < n; i++ {
|
||||||
blocks[i] = newBlock(uint32(i+1), newMinerTX())
|
blocks[i] = newBlock(uint32(i+1), newMinerTX())
|
||||||
}
|
}
|
||||||
|
@ -108,7 +109,7 @@ func newMinerTX() *transaction.Transaction {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getDecodedBlock(t *testing.T, i int) *Block {
|
func getDecodedBlock(t *testing.T, i int) *block.Block {
|
||||||
data, err := getBlockData(i)
|
data, err := getBlockData(i)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
|
@ -119,7 +120,7 @@ func getDecodedBlock(t *testing.T, i int) *Block {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
block := &Block{}
|
block := &block.Block{}
|
||||||
r := io.NewBinReaderFromBuf(b)
|
r := io.NewBinReaderFromBuf(b)
|
||||||
block.DecodeBinary(r)
|
block.DecodeBinary(r)
|
||||||
if r.Err != nil {
|
if r.Err != nil {
|
||||||
|
@ -140,3 +141,25 @@ func getBlockData(i int) (map[string]interface{}, error) {
|
||||||
}
|
}
|
||||||
return data, err
|
return data, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func newDumbBlock() *block.Block {
|
||||||
|
return &block.Block{
|
||||||
|
Base: block.Base{
|
||||||
|
Version: 0,
|
||||||
|
PrevHash: hash.Sha256([]byte("a")),
|
||||||
|
MerkleRoot: hash.Sha256([]byte("b")),
|
||||||
|
Timestamp: uint32(100500),
|
||||||
|
Index: 1,
|
||||||
|
ConsensusData: 1111,
|
||||||
|
NextConsensus: hash.Hash160([]byte("a")),
|
||||||
|
Script: transaction.Witness{
|
||||||
|
VerificationScript: []byte{0x51}, // PUSH1
|
||||||
|
InvocationScript: []byte{0x61}, // NOP
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Transactions: []*transaction.Transaction{
|
||||||
|
{Type: transaction.MinerType},
|
||||||
|
{Type: transaction.IssueType},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"math/big"
|
"math/big"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/CityOfZion/neo-go/pkg/core/block"
|
||||||
"github.com/CityOfZion/neo-go/pkg/core/state"
|
"github.com/CityOfZion/neo-go/pkg/core/state"
|
||||||
"github.com/CityOfZion/neo-go/pkg/core/storage"
|
"github.com/CityOfZion/neo-go/pkg/core/storage"
|
||||||
"github.com/CityOfZion/neo-go/pkg/core/transaction"
|
"github.com/CityOfZion/neo-go/pkg/core/transaction"
|
||||||
|
@ -451,7 +452,7 @@ func TestAssetGetPrecision(t *testing.T) {
|
||||||
|
|
||||||
// Helper functions to create VM, InteropContext, TX, Account, Contract, Asset.
|
// Helper functions to create VM, InteropContext, TX, Account, Contract, Asset.
|
||||||
|
|
||||||
func createVMAndPushBlock(t *testing.T) (*vm.VM, *Block, *interopContext, *Blockchain) {
|
func createVMAndPushBlock(t *testing.T) (*vm.VM, *block.Block, *interopContext, *Blockchain) {
|
||||||
v := vm.New()
|
v := vm.New()
|
||||||
block := newDumbBlock()
|
block := newDumbBlock()
|
||||||
chain := newTestChain(t)
|
chain := newTestChain(t)
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
|
|
||||||
|
"github.com/CityOfZion/neo-go/pkg/core/block"
|
||||||
"github.com/CityOfZion/neo-go/pkg/core/state"
|
"github.com/CityOfZion/neo-go/pkg/core/state"
|
||||||
"github.com/CityOfZion/neo-go/pkg/core/transaction"
|
"github.com/CityOfZion/neo-go/pkg/core/transaction"
|
||||||
"github.com/CityOfZion/neo-go/pkg/crypto/hash"
|
"github.com/CityOfZion/neo-go/pkg/crypto/hash"
|
||||||
|
@ -132,11 +133,11 @@ func (ic *interopContext) bcGetTransactionHeight(v *vm.VM) error {
|
||||||
// popHeaderFromVM returns pointer to Header or error. It's main feature is
|
// popHeaderFromVM returns pointer to Header or error. It's main feature is
|
||||||
// proper treatment of Block structure, because C# code implicitly assumes
|
// proper treatment of Block structure, because C# code implicitly assumes
|
||||||
// that header APIs can also operate on blocks.
|
// that header APIs can also operate on blocks.
|
||||||
func popHeaderFromVM(v *vm.VM) (*Header, error) {
|
func popHeaderFromVM(v *vm.VM) (*block.Header, error) {
|
||||||
iface := v.Estack().Pop().Value()
|
iface := v.Estack().Pop().Value()
|
||||||
header, ok := iface.(*Header)
|
header, ok := iface.(*block.Header)
|
||||||
if !ok {
|
if !ok {
|
||||||
block, ok := iface.(*Block)
|
block, ok := iface.(*block.Block)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.New("value is not a header or block")
|
return nil, errors.New("value is not a header or block")
|
||||||
}
|
}
|
||||||
|
@ -188,7 +189,7 @@ func (ic *interopContext) headerGetTimestamp(v *vm.VM) error {
|
||||||
// blockGetTransactionCount returns transactions count in the given block.
|
// blockGetTransactionCount returns transactions count in the given block.
|
||||||
func (ic *interopContext) blockGetTransactionCount(v *vm.VM) error {
|
func (ic *interopContext) blockGetTransactionCount(v *vm.VM) error {
|
||||||
blockInterface := v.Estack().Pop().Value()
|
blockInterface := v.Estack().Pop().Value()
|
||||||
block, ok := blockInterface.(*Block)
|
block, ok := blockInterface.(*block.Block)
|
||||||
if !ok {
|
if !ok {
|
||||||
return errors.New("value is not a block")
|
return errors.New("value is not a block")
|
||||||
}
|
}
|
||||||
|
@ -199,7 +200,7 @@ func (ic *interopContext) blockGetTransactionCount(v *vm.VM) error {
|
||||||
// blockGetTransactions returns transactions from the given block.
|
// blockGetTransactions returns transactions from the given block.
|
||||||
func (ic *interopContext) blockGetTransactions(v *vm.VM) error {
|
func (ic *interopContext) blockGetTransactions(v *vm.VM) error {
|
||||||
blockInterface := v.Estack().Pop().Value()
|
blockInterface := v.Estack().Pop().Value()
|
||||||
block, ok := blockInterface.(*Block)
|
block, ok := blockInterface.(*block.Block)
|
||||||
if !ok {
|
if !ok {
|
||||||
return errors.New("value is not a block")
|
return errors.New("value is not a block")
|
||||||
}
|
}
|
||||||
|
@ -218,7 +219,7 @@ func (ic *interopContext) blockGetTransactions(v *vm.VM) error {
|
||||||
// block.
|
// block.
|
||||||
func (ic *interopContext) blockGetTransaction(v *vm.VM) error {
|
func (ic *interopContext) blockGetTransaction(v *vm.VM) error {
|
||||||
blockInterface := v.Estack().Pop().Value()
|
blockInterface := v.Estack().Pop().Value()
|
||||||
block, ok := blockInterface.(*Block)
|
block, ok := blockInterface.(*block.Block)
|
||||||
if !ok {
|
if !ok {
|
||||||
return errors.New("value is not a block")
|
return errors.New("value is not a block")
|
||||||
}
|
}
|
||||||
|
@ -359,7 +360,7 @@ func (ic *interopContext) runtimeLog(v *vm.VM) error {
|
||||||
// runtimeGetTime returns timestamp of the block being verified, or the latest
|
// runtimeGetTime returns timestamp of the block being verified, or the latest
|
||||||
// one in the blockchain if no block is given to interopContext.
|
// one in the blockchain if no block is given to interopContext.
|
||||||
func (ic *interopContext) runtimeGetTime(v *vm.VM) error {
|
func (ic *interopContext) runtimeGetTime(v *vm.VM) error {
|
||||||
var header *Header
|
var header *block.Header
|
||||||
if ic.block == nil {
|
if ic.block == nil {
|
||||||
var err error
|
var err error
|
||||||
header, err = ic.bc.GetHeader(ic.bc.CurrentBlockHash())
|
header, err = ic.bc.GetHeader(ic.bc.CurrentBlockHash())
|
||||||
|
|
|
@ -10,6 +10,7 @@ package core
|
||||||
import (
|
import (
|
||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
|
"github.com/CityOfZion/neo-go/pkg/core/block"
|
||||||
"github.com/CityOfZion/neo-go/pkg/core/state"
|
"github.com/CityOfZion/neo-go/pkg/core/state"
|
||||||
"github.com/CityOfZion/neo-go/pkg/core/storage"
|
"github.com/CityOfZion/neo-go/pkg/core/storage"
|
||||||
"github.com/CityOfZion/neo-go/pkg/core/transaction"
|
"github.com/CityOfZion/neo-go/pkg/core/transaction"
|
||||||
|
@ -20,14 +21,14 @@ import (
|
||||||
type interopContext struct {
|
type interopContext struct {
|
||||||
bc Blockchainer
|
bc Blockchainer
|
||||||
trigger byte
|
trigger byte
|
||||||
block *Block
|
block *block.Block
|
||||||
tx *transaction.Transaction
|
tx *transaction.Transaction
|
||||||
dao *cachedDao
|
dao *cachedDao
|
||||||
notifications []state.NotificationEvent
|
notifications []state.NotificationEvent
|
||||||
log *zap.Logger
|
log *zap.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
func newInteropContext(trigger byte, bc Blockchainer, s storage.Store, block *Block, tx *transaction.Transaction, log *zap.Logger) *interopContext {
|
func newInteropContext(trigger byte, bc Blockchainer, s storage.Store, block *block.Block, tx *transaction.Transaction, log *zap.Logger) *interopContext {
|
||||||
dao := newCachedDao(s)
|
dao := newCachedDao(s)
|
||||||
nes := make([]state.NotificationEvent, 0)
|
nes := make([]state.NotificationEvent, 0)
|
||||||
return &interopContext{bc, trigger, block, tx, dao, nes, log}
|
return &interopContext{bc, trigger, block, tx, dao, nes, log}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package core
|
package mempool
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/CityOfZion/neo-go/pkg/core/transaction"
|
"github.com/CityOfZion/neo-go/pkg/core/transaction"
|
|
@ -1,4 +1,4 @@
|
||||||
package core
|
package mempool
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"sort"
|
"sort"
|
||||||
|
@ -9,38 +9,38 @@ import (
|
||||||
"github.com/CityOfZion/neo-go/pkg/util"
|
"github.com/CityOfZion/neo-go/pkg/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
// PoolItem represents a transaction in the the Memory pool.
|
// Item represents a transaction in the the Memory pool.
|
||||||
type PoolItem struct {
|
type Item struct {
|
||||||
txn *transaction.Transaction
|
txn *transaction.Transaction
|
||||||
timeStamp time.Time
|
timeStamp time.Time
|
||||||
fee Feer
|
fee Feer
|
||||||
}
|
}
|
||||||
|
|
||||||
// PoolItems slice of PoolItem.
|
// Items is a slice of Item.
|
||||||
type PoolItems []*PoolItem
|
type Items []*Item
|
||||||
|
|
||||||
// MemPool stores the unconfirms transactions.
|
// Pool stores the unconfirms transactions.
|
||||||
type MemPool struct {
|
type Pool struct {
|
||||||
lock *sync.RWMutex
|
lock *sync.RWMutex
|
||||||
unsortedTxn map[util.Uint256]*PoolItem
|
unsortedTxn map[util.Uint256]*Item
|
||||||
unverifiedTxn map[util.Uint256]*PoolItem
|
unverifiedTxn map[util.Uint256]*Item
|
||||||
sortedHighPrioTxn PoolItems
|
sortedHighPrioTxn Items
|
||||||
sortedLowPrioTxn PoolItems
|
sortedLowPrioTxn Items
|
||||||
unverifiedSortedHighPrioTxn PoolItems
|
unverifiedSortedHighPrioTxn Items
|
||||||
unverifiedSortedLowPrioTxn PoolItems
|
unverifiedSortedLowPrioTxn Items
|
||||||
|
|
||||||
capacity int
|
capacity int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p PoolItems) Len() int { return len(p) }
|
func (p Items) Len() int { return len(p) }
|
||||||
func (p PoolItems) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
|
func (p Items) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
|
||||||
func (p PoolItems) Less(i, j int) bool { return p[i].CompareTo(p[j]) < 0 }
|
func (p Items) Less(i, j int) bool { return p[i].CompareTo(p[j]) < 0 }
|
||||||
|
|
||||||
// CompareTo returns the difference between two PoolItems.
|
// CompareTo returns the difference between two Items.
|
||||||
// difference < 0 implies p < otherP.
|
// difference < 0 implies p < otherP.
|
||||||
// difference = 0 implies p = otherP.
|
// difference = 0 implies p = otherP.
|
||||||
// difference > 0 implies p > otherP.
|
// difference > 0 implies p > otherP.
|
||||||
func (p PoolItem) CompareTo(otherP *PoolItem) int {
|
func (p Item) CompareTo(otherP *Item) int {
|
||||||
if otherP == nil {
|
if otherP == nil {
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
@ -77,15 +77,15 @@ func (p PoolItem) CompareTo(otherP *PoolItem) int {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Count returns the total number of uncofirm transactions.
|
// Count returns the total number of uncofirm transactions.
|
||||||
func (mp MemPool) Count() int {
|
func (mp Pool) Count() int {
|
||||||
mp.lock.RLock()
|
mp.lock.RLock()
|
||||||
defer mp.lock.RUnlock()
|
defer mp.lock.RUnlock()
|
||||||
|
|
||||||
return len(mp.unsortedTxn) + len(mp.unverifiedTxn)
|
return len(mp.unsortedTxn) + len(mp.unverifiedTxn)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ContainsKey checks if a transactions hash is in the MemPool.
|
// ContainsKey checks if a transactions hash is in the Pool.
|
||||||
func (mp MemPool) ContainsKey(hash util.Uint256) bool {
|
func (mp Pool) ContainsKey(hash util.Uint256) bool {
|
||||||
mp.lock.RLock()
|
mp.lock.RLock()
|
||||||
defer mp.lock.RUnlock()
|
defer mp.lock.RUnlock()
|
||||||
|
|
||||||
|
@ -100,9 +100,9 @@ func (mp MemPool) ContainsKey(hash util.Uint256) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// TryAdd try to add the PoolItem to the MemPool.
|
// TryAdd try to add the Item to the Pool.
|
||||||
func (mp MemPool) TryAdd(hash util.Uint256, pItem *PoolItem) bool {
|
func (mp Pool) TryAdd(hash util.Uint256, pItem *Item) bool {
|
||||||
var pool PoolItems
|
var pool Items
|
||||||
|
|
||||||
mp.lock.Lock()
|
mp.lock.Lock()
|
||||||
if _, ok := mp.unsortedTxn[hash]; ok {
|
if _, ok := mp.unsortedTxn[hash]; ok {
|
||||||
|
@ -135,13 +135,13 @@ func (mp MemPool) TryAdd(hash util.Uint256, pItem *PoolItem) bool {
|
||||||
|
|
||||||
// Remove removes an item from the mempool, if it exists there (and does
|
// Remove removes an item from the mempool, if it exists there (and does
|
||||||
// nothing if it doesn't).
|
// nothing if it doesn't).
|
||||||
func (mp *MemPool) Remove(hash util.Uint256) {
|
func (mp *Pool) Remove(hash util.Uint256) {
|
||||||
var mapAndPools = []struct {
|
var mapAndPools = []struct {
|
||||||
unsortedMap map[util.Uint256]*PoolItem
|
unsortedMap map[util.Uint256]*Item
|
||||||
sortedPools []*PoolItems
|
sortedPools []*Items
|
||||||
}{
|
}{
|
||||||
{unsortedMap: mp.unsortedTxn, sortedPools: []*PoolItems{&mp.sortedHighPrioTxn, &mp.sortedLowPrioTxn}},
|
{unsortedMap: mp.unsortedTxn, sortedPools: []*Items{&mp.sortedHighPrioTxn, &mp.sortedLowPrioTxn}},
|
||||||
{unsortedMap: mp.unverifiedTxn, sortedPools: []*PoolItems{&mp.unverifiedSortedHighPrioTxn, &mp.unverifiedSortedLowPrioTxn}},
|
{unsortedMap: mp.unverifiedTxn, sortedPools: []*Items{&mp.unverifiedSortedHighPrioTxn, &mp.unverifiedSortedLowPrioTxn}},
|
||||||
}
|
}
|
||||||
mp.lock.Lock()
|
mp.lock.Lock()
|
||||||
for _, mapAndPool := range mapAndPools {
|
for _, mapAndPool := range mapAndPools {
|
||||||
|
@ -149,7 +149,7 @@ func (mp *MemPool) Remove(hash util.Uint256) {
|
||||||
delete(mapAndPool.unsortedMap, hash)
|
delete(mapAndPool.unsortedMap, hash)
|
||||||
for _, pool := range mapAndPool.sortedPools {
|
for _, pool := range mapAndPool.sortedPools {
|
||||||
var num int
|
var num int
|
||||||
var item *PoolItem
|
var item *Item
|
||||||
for num, item = range *pool {
|
for num, item = range *pool {
|
||||||
if hash.Equals(item.txn.Hash()) {
|
if hash.Equals(item.txn.Hash()) {
|
||||||
break
|
break
|
||||||
|
@ -168,8 +168,8 @@ func (mp *MemPool) Remove(hash util.Uint256) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveOverCapacity removes transactions with lowest fees until the total number of transactions
|
// RemoveOverCapacity removes transactions with lowest fees until the total number of transactions
|
||||||
// in the MemPool is within the capacity of the MemPool.
|
// in the Pool is within the capacity of the Pool.
|
||||||
func (mp *MemPool) RemoveOverCapacity() {
|
func (mp *Pool) RemoveOverCapacity() {
|
||||||
for mp.Count()-mp.capacity > 0 {
|
for mp.Count()-mp.capacity > 0 {
|
||||||
mp.lock.Lock()
|
mp.lock.Lock()
|
||||||
if minItem, argPosition := getLowestFeeTransaction(mp.sortedLowPrioTxn, mp.unverifiedSortedLowPrioTxn); minItem != nil {
|
if minItem, argPosition := getLowestFeeTransaction(mp.sortedLowPrioTxn, mp.unverifiedSortedLowPrioTxn); minItem != nil {
|
||||||
|
@ -205,27 +205,27 @@ func (mp *MemPool) RemoveOverCapacity() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewPoolItem returns a new PoolItem.
|
// NewPoolItem returns a new Item.
|
||||||
func NewPoolItem(t *transaction.Transaction, fee Feer) *PoolItem {
|
func NewPoolItem(t *transaction.Transaction, fee Feer) *Item {
|
||||||
return &PoolItem{
|
return &Item{
|
||||||
txn: t,
|
txn: t,
|
||||||
timeStamp: time.Now().UTC(),
|
timeStamp: time.Now().UTC(),
|
||||||
fee: fee,
|
fee: fee,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewMemPool returns a new MemPool struct.
|
// NewMemPool returns a new Pool struct.
|
||||||
func NewMemPool(capacity int) MemPool {
|
func NewMemPool(capacity int) Pool {
|
||||||
return MemPool{
|
return Pool{
|
||||||
lock: new(sync.RWMutex),
|
lock: new(sync.RWMutex),
|
||||||
unsortedTxn: make(map[util.Uint256]*PoolItem),
|
unsortedTxn: make(map[util.Uint256]*Item),
|
||||||
unverifiedTxn: make(map[util.Uint256]*PoolItem),
|
unverifiedTxn: make(map[util.Uint256]*Item),
|
||||||
capacity: capacity,
|
capacity: capacity,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TryGetValue returns a transaction if it exists in the memory pool.
|
// TryGetValue returns a transaction if it exists in the memory pool.
|
||||||
func (mp MemPool) TryGetValue(hash util.Uint256) (*transaction.Transaction, bool) {
|
func (mp Pool) TryGetValue(hash util.Uint256) (*transaction.Transaction, bool) {
|
||||||
mp.lock.RLock()
|
mp.lock.RLock()
|
||||||
defer mp.lock.RUnlock()
|
defer mp.lock.RUnlock()
|
||||||
if pItem, ok := mp.unsortedTxn[hash]; ok {
|
if pItem, ok := mp.unsortedTxn[hash]; ok {
|
||||||
|
@ -239,13 +239,13 @@ func (mp MemPool) TryGetValue(hash util.Uint256) (*transaction.Transaction, bool
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
// getLowestFeeTransaction returns the PoolItem with the lowest fee amongst the "verifiedTxnSorted"
|
// getLowestFeeTransaction returns the Item with the lowest fee amongst the "verifiedTxnSorted"
|
||||||
// and "unverifiedTxnSorted" PoolItems along with a integer. The integer can assume two values, 1 and 2 which indicate
|
// and "unverifiedTxnSorted" Items along with a integer. The integer can assume two values, 1 and 2 which indicate
|
||||||
// that the PoolItem with the lowest fee was found in "verifiedTxnSorted" respectively in "unverifiedTxnSorted".
|
// that the Item with the lowest fee was found in "verifiedTxnSorted" respectively in "unverifiedTxnSorted".
|
||||||
// "verifiedTxnSorted" and "unverifiedTxnSorted" are sorted slice order by transaction fee ascending. This means that
|
// "verifiedTxnSorted" and "unverifiedTxnSorted" are sorted slice order by transaction fee ascending. This means that
|
||||||
// the transaction with lowest fee start at index 0.
|
// the transaction with lowest fee start at index 0.
|
||||||
// Reference: GetLowestFeeTransaction method in C# (https://github.com/neo-project/neo/blob/master/neo/Ledger/MemoryPool.cs)
|
// Reference: GetLowestFeeTransaction method in C# (https://github.com/neo-project/neo/blob/master/neo/Ledger/MemoryPool.cs)
|
||||||
func getLowestFeeTransaction(verifiedTxnSorted PoolItems, unverifiedTxnSorted PoolItems) (*PoolItem, int) {
|
func getLowestFeeTransaction(verifiedTxnSorted Items, unverifiedTxnSorted Items) (*Item, int) {
|
||||||
minItem := min(unverifiedTxnSorted)
|
minItem := min(unverifiedTxnSorted)
|
||||||
verifiedMin := min(verifiedTxnSorted)
|
verifiedMin := min(verifiedTxnSorted)
|
||||||
if verifiedMin == nil || (minItem != nil && verifiedMin.CompareTo(minItem) >= 0) {
|
if verifiedMin == nil || (minItem != nil && verifiedMin.CompareTo(minItem) >= 0) {
|
||||||
|
@ -259,7 +259,7 @@ func getLowestFeeTransaction(verifiedTxnSorted PoolItems, unverifiedTxnSorted Po
|
||||||
|
|
||||||
// min returns the minimum item in a ascending sorted slice of pool items.
|
// min returns the minimum item in a ascending sorted slice of pool items.
|
||||||
// The function can't be applied to unsorted slice!
|
// The function can't be applied to unsorted slice!
|
||||||
func min(sortedPool PoolItems) *PoolItem {
|
func min(sortedPool Items) *Item {
|
||||||
if len(sortedPool) == 0 {
|
if len(sortedPool) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -268,7 +268,7 @@ func min(sortedPool PoolItems) *PoolItem {
|
||||||
|
|
||||||
// GetVerifiedTransactions returns a slice of Input from all the transactions in the memory pool
|
// GetVerifiedTransactions returns a slice of Input from all the transactions in the memory pool
|
||||||
// whose hash is not included in excludedHashes.
|
// whose hash is not included in excludedHashes.
|
||||||
func (mp *MemPool) GetVerifiedTransactions() []*transaction.Transaction {
|
func (mp *Pool) GetVerifiedTransactions() []*transaction.Transaction {
|
||||||
mp.lock.RLock()
|
mp.lock.RLock()
|
||||||
defer mp.lock.RUnlock()
|
defer mp.lock.RUnlock()
|
||||||
|
|
||||||
|
@ -286,7 +286,7 @@ func (mp *MemPool) GetVerifiedTransactions() []*transaction.Transaction {
|
||||||
// Verify verifies if the inputs of a transaction tx are already used in any other transaction in the memory pool.
|
// Verify verifies if the inputs of a transaction tx are already used in any other transaction in the memory pool.
|
||||||
// If yes, the transaction tx is not a valid transaction and the function return false.
|
// If yes, the transaction tx is not a valid transaction and the function return false.
|
||||||
// If no, the transaction tx is a valid transaction and the function return true.
|
// If no, the transaction tx is a valid transaction and the function return true.
|
||||||
func (mp MemPool) Verify(tx *transaction.Transaction) bool {
|
func (mp Pool) Verify(tx *transaction.Transaction) bool {
|
||||||
mp.lock.RLock()
|
mp.lock.RLock()
|
||||||
defer mp.lock.RUnlock()
|
defer mp.lock.RUnlock()
|
||||||
for _, item := range mp.unsortedTxn {
|
for _, item := range mp.unsortedTxn {
|
|
@ -1,4 +1,4 @@
|
||||||
package core
|
package mempool
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
@ -88,3 +88,10 @@ func TestMemPoolVerify(t *testing.T) {
|
||||||
tx3.Inputs = append(tx3.Inputs, transaction.Input{PrevHash: inhash2, PrevIndex: 0})
|
tx3.Inputs = append(tx3.Inputs, transaction.Input{PrevHash: inhash2, PrevIndex: 0})
|
||||||
require.Equal(t, false, mp.Verify(tx3))
|
require.Equal(t, false, mp.Verify(tx3))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func newMinerTX() *transaction.Transaction {
|
||||||
|
return &transaction.Transaction{
|
||||||
|
Type: transaction.MinerType,
|
||||||
|
Data: &transaction.MinerTX{},
|
||||||
|
}
|
||||||
|
}
|
34
pkg/core/mempool/prometheus.go
Normal file
34
pkg/core/mempool/prometheus.go
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
package mempool
|
||||||
|
|
||||||
|
import "github.com/prometheus/client_golang/prometheus"
|
||||||
|
|
||||||
|
var (
|
||||||
|
//mempoolUnsortedTx prometheus metric.
|
||||||
|
mempoolUnsortedTx = prometheus.NewGauge(
|
||||||
|
prometheus.GaugeOpts{
|
||||||
|
Help: "Mempool Unsorted TXs",
|
||||||
|
Name: "mempool_unsorted_tx",
|
||||||
|
Namespace: "neogo",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
//mempoolUnverifiedTx prometheus metric.
|
||||||
|
mempoolUnverifiedTx = prometheus.NewGauge(
|
||||||
|
prometheus.GaugeOpts{
|
||||||
|
Help: "Mempool Unverified TXs",
|
||||||
|
Name: "mempool_unverified_tx",
|
||||||
|
Namespace: "neogo",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
prometheus.MustRegister(
|
||||||
|
mempoolUnsortedTx,
|
||||||
|
mempoolUnverifiedTx,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateMempoolMetrics(unsortedTxnLen int, unverifiedTxnLen int) {
|
||||||
|
mempoolUnsortedTx.Set(float64(unsortedTxnLen))
|
||||||
|
mempoolUnverifiedTx.Set(float64(unverifiedTxnLen))
|
||||||
|
}
|
|
@ -30,22 +30,6 @@ var (
|
||||||
Namespace: "neogo",
|
Namespace: "neogo",
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
//mempoolUnsortedTx prometheus metric.
|
|
||||||
mempoolUnsortedTx = prometheus.NewGauge(
|
|
||||||
prometheus.GaugeOpts{
|
|
||||||
Help: "Mempool Unsorted TXs",
|
|
||||||
Name: "mempool_unsorted_tx",
|
|
||||||
Namespace: "neogo",
|
|
||||||
},
|
|
||||||
)
|
|
||||||
//mempoolUnverifiedTx prometheus metric.
|
|
||||||
mempoolUnverifiedTx = prometheus.NewGauge(
|
|
||||||
prometheus.GaugeOpts{
|
|
||||||
Help: "Mempool Unverified TXs",
|
|
||||||
Name: "mempool_unverified_tx",
|
|
||||||
Namespace: "neogo",
|
|
||||||
},
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
@ -53,8 +37,6 @@ func init() {
|
||||||
blockHeight,
|
blockHeight,
|
||||||
persistedHeight,
|
persistedHeight,
|
||||||
headerHeight,
|
headerHeight,
|
||||||
mempoolUnsortedTx,
|
|
||||||
mempoolUnverifiedTx,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,8 +51,3 @@ func updateHeaderHeightMetric(hHeight int) {
|
||||||
func updateBlockHeightMetric(bHeight uint32) {
|
func updateBlockHeightMetric(bHeight uint32) {
|
||||||
blockHeight.Set(float64(bHeight))
|
blockHeight.Set(float64(bHeight))
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateMempoolMetrics(unsortedTxnLen int, unverifiedTxnLen int) {
|
|
||||||
mempoolUnsortedTx.Set(float64(unsortedTxnLen))
|
|
||||||
mempoolUnverifiedTx.Set(float64(unverifiedTxnLen))
|
|
||||||
}
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/CityOfZion/neo-go/config"
|
"github.com/CityOfZion/neo-go/config"
|
||||||
|
"github.com/CityOfZion/neo-go/pkg/core/block"
|
||||||
"github.com/CityOfZion/neo-go/pkg/core/transaction"
|
"github.com/CityOfZion/neo-go/pkg/core/transaction"
|
||||||
"github.com/CityOfZion/neo-go/pkg/crypto/hash"
|
"github.com/CityOfZion/neo-go/pkg/crypto/hash"
|
||||||
"github.com/CityOfZion/neo-go/pkg/crypto/keys"
|
"github.com/CityOfZion/neo-go/pkg/crypto/keys"
|
||||||
|
@ -13,7 +14,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// createGenesisBlock creates a genesis block based on the given configuration.
|
// createGenesisBlock creates a genesis block based on the given configuration.
|
||||||
func createGenesisBlock(cfg config.ProtocolConfiguration) (*Block, error) {
|
func createGenesisBlock(cfg config.ProtocolConfiguration) (*block.Block, error) {
|
||||||
validators, err := getValidators(cfg)
|
validators, err := getValidators(cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -24,7 +25,7 @@ func createGenesisBlock(cfg config.ProtocolConfiguration) (*Block, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
base := BlockBase{
|
base := block.Base{
|
||||||
Version: 0,
|
Version: 0,
|
||||||
PrevHash: util.Uint256{},
|
PrevHash: util.Uint256{},
|
||||||
Timestamp: uint32(time.Date(2016, 7, 15, 15, 8, 21, 0, time.UTC).Unix()),
|
Timestamp: uint32(time.Date(2016, 7, 15, 15, 8, 21, 0, time.UTC).Unix()),
|
||||||
|
@ -48,8 +49,8 @@ func createGenesisBlock(cfg config.ProtocolConfiguration) (*Block, error) {
|
||||||
}
|
}
|
||||||
scriptOut := hash.Hash160(rawScript)
|
scriptOut := hash.Hash160(rawScript)
|
||||||
|
|
||||||
block := &Block{
|
b := &block.Block{
|
||||||
BlockBase: base,
|
Base: base,
|
||||||
Transactions: []*transaction.Transaction{
|
Transactions: []*transaction.Transaction{
|
||||||
{
|
{
|
||||||
Type: transaction.MinerType,
|
Type: transaction.MinerType,
|
||||||
|
@ -84,11 +85,11 @@ func createGenesisBlock(cfg config.ProtocolConfiguration) (*Block, error) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = block.rebuildMerkleRoot(); err != nil {
|
if err = b.RebuildMerkleRoot(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return block, nil
|
return b, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func governingTokenTX() *transaction.Transaction {
|
func governingTokenTX() *transaction.Transaction {
|
||||||
|
@ -167,7 +168,7 @@ func calculateUtilityAmount() util.Fixed8 {
|
||||||
}
|
}
|
||||||
|
|
||||||
// headerSliceReverse reverses the given slice of *Header.
|
// headerSliceReverse reverses the given slice of *Header.
|
||||||
func headerSliceReverse(dest []*Header) {
|
func headerSliceReverse(dest []*block.Header) {
|
||||||
for i, j := 0, len(dest)-1; i < j; i, j = i+1, j-1 {
|
for i, j := 0, len(dest)-1; i < j; i, j = i+1, j-1 {
|
||||||
dest[i], dest[j] = dest[j], dest[i]
|
dest[i], dest[j] = dest[j], dest[i]
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package network
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/CityOfZion/neo-go/pkg/core"
|
"github.com/CityOfZion/neo-go/pkg/core"
|
||||||
|
"github.com/CityOfZion/neo-go/pkg/core/block"
|
||||||
"github.com/Workiva/go-datastructures/queue"
|
"github.com/Workiva/go-datastructures/queue"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
@ -37,7 +38,7 @@ func (bq *blockQueue) run() {
|
||||||
if item == nil {
|
if item == nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
minblock := item.(*core.Block)
|
minblock := item.(*block.Block)
|
||||||
if minblock.Index <= bq.chain.BlockHeight()+1 {
|
if minblock.Index <= bq.chain.BlockHeight()+1 {
|
||||||
_, _ = bq.queue.Get(1)
|
_, _ = bq.queue.Get(1)
|
||||||
updateBlockQueueLenMetric(bq.length())
|
updateBlockQueueLenMetric(bq.length())
|
||||||
|
@ -57,7 +58,7 @@ func (bq *blockQueue) run() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bq *blockQueue) putBlock(block *core.Block) error {
|
func (bq *blockQueue) putBlock(block *block.Block) error {
|
||||||
if bq.chain.BlockHeight() >= block.Index {
|
if bq.chain.BlockHeight() >= block.Index {
|
||||||
// can easily happen when fetching the same blocks from
|
// can easily happen when fetching the same blocks from
|
||||||
// different peers, thus not considered as error
|
// different peers, thus not considered as error
|
||||||
|
|
|
@ -4,7 +4,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/CityOfZion/neo-go/pkg/core"
|
"github.com/CityOfZion/neo-go/pkg/core/block"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"go.uber.org/zap/zaptest"
|
"go.uber.org/zap/zaptest"
|
||||||
)
|
)
|
||||||
|
@ -13,9 +13,9 @@ func TestBlockQueue(t *testing.T) {
|
||||||
chain := &testChain{}
|
chain := &testChain{}
|
||||||
// notice, it's not yet running
|
// notice, it's not yet running
|
||||||
bq := newBlockQueue(0, chain, zaptest.NewLogger(t))
|
bq := newBlockQueue(0, chain, zaptest.NewLogger(t))
|
||||||
blocks := make([]*core.Block, 11)
|
blocks := make([]*block.Block, 11)
|
||||||
for i := 1; i < 11; i++ {
|
for i := 1; i < 11; i++ {
|
||||||
blocks[i] = &core.Block{BlockBase: core.BlockBase{Index: uint32(i)}}
|
blocks[i] = &block.Block{Base: block.Base{Index: uint32(i)}}
|
||||||
}
|
}
|
||||||
// not the ones expected currently
|
// not the ones expected currently
|
||||||
for i := 3; i < 5; i++ {
|
for i := 3; i < 5; i++ {
|
||||||
|
|
|
@ -9,6 +9,8 @@ import (
|
||||||
|
|
||||||
"github.com/CityOfZion/neo-go/config"
|
"github.com/CityOfZion/neo-go/config"
|
||||||
"github.com/CityOfZion/neo-go/pkg/core"
|
"github.com/CityOfZion/neo-go/pkg/core"
|
||||||
|
"github.com/CityOfZion/neo-go/pkg/core/block"
|
||||||
|
"github.com/CityOfZion/neo-go/pkg/core/mempool"
|
||||||
"github.com/CityOfZion/neo-go/pkg/core/state"
|
"github.com/CityOfZion/neo-go/pkg/core/state"
|
||||||
"github.com/CityOfZion/neo-go/pkg/core/storage"
|
"github.com/CityOfZion/neo-go/pkg/core/storage"
|
||||||
"github.com/CityOfZion/neo-go/pkg/core/transaction"
|
"github.com/CityOfZion/neo-go/pkg/core/transaction"
|
||||||
|
@ -43,10 +45,10 @@ func (chain testChain) NetworkFee(t *transaction.Transaction) util.Fixed8 {
|
||||||
panic("TODO")
|
panic("TODO")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (chain testChain) AddHeaders(...*core.Header) error {
|
func (chain testChain) AddHeaders(...*block.Header) error {
|
||||||
panic("TODO")
|
panic("TODO")
|
||||||
}
|
}
|
||||||
func (chain *testChain) AddBlock(block *core.Block) error {
|
func (chain *testChain) AddBlock(block *block.Block) error {
|
||||||
if block.Index == chain.blockheight+1 {
|
if block.Index == chain.blockheight+1 {
|
||||||
atomic.StoreUint32(&chain.blockheight, block.Index)
|
atomic.StoreUint32(&chain.blockheight, block.Index)
|
||||||
}
|
}
|
||||||
|
@ -61,7 +63,7 @@ func (chain *testChain) Close() {
|
||||||
func (chain testChain) HeaderHeight() uint32 {
|
func (chain testChain) HeaderHeight() uint32 {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
func (chain testChain) GetBlock(hash util.Uint256) (*core.Block, error) {
|
func (chain testChain) GetBlock(hash util.Uint256) (*block.Block, error) {
|
||||||
panic("TODO")
|
panic("TODO")
|
||||||
}
|
}
|
||||||
func (chain testChain) GetContractState(hash util.Uint160) *state.Contract {
|
func (chain testChain) GetContractState(hash util.Uint160) *state.Contract {
|
||||||
|
@ -70,7 +72,7 @@ func (chain testChain) GetContractState(hash util.Uint160) *state.Contract {
|
||||||
func (chain testChain) GetHeaderHash(int) util.Uint256 {
|
func (chain testChain) GetHeaderHash(int) util.Uint256 {
|
||||||
return util.Uint256{}
|
return util.Uint256{}
|
||||||
}
|
}
|
||||||
func (chain testChain) GetHeader(hash util.Uint256) (*core.Header, error) {
|
func (chain testChain) GetHeader(hash util.Uint256) (*block.Header, error) {
|
||||||
panic("TODO")
|
panic("TODO")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,7 +117,7 @@ func (chain testChain) GetUnspentCoinState(util.Uint256) *core.UnspentCoinState
|
||||||
panic("TODO")
|
panic("TODO")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (chain testChain) GetMemPool() core.MemPool {
|
func (chain testChain) GetMemPool() mempool.Pool {
|
||||||
panic("TODO")
|
panic("TODO")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -123,7 +125,7 @@ func (chain testChain) IsLowPriority(*transaction.Transaction) bool {
|
||||||
panic("TODO")
|
panic("TODO")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (chain testChain) VerifyTx(*transaction.Transaction, *core.Block) error {
|
func (chain testChain) VerifyTx(*transaction.Transaction, *block.Block) error {
|
||||||
panic("TODO")
|
panic("TODO")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ import (
|
||||||
|
|
||||||
"github.com/CityOfZion/neo-go/config"
|
"github.com/CityOfZion/neo-go/config"
|
||||||
"github.com/CityOfZion/neo-go/pkg/consensus"
|
"github.com/CityOfZion/neo-go/pkg/consensus"
|
||||||
"github.com/CityOfZion/neo-go/pkg/core"
|
"github.com/CityOfZion/neo-go/pkg/core/block"
|
||||||
"github.com/CityOfZion/neo-go/pkg/core/transaction"
|
"github.com/CityOfZion/neo-go/pkg/core/transaction"
|
||||||
"github.com/CityOfZion/neo-go/pkg/crypto/hash"
|
"github.com/CityOfZion/neo-go/pkg/crypto/hash"
|
||||||
"github.com/CityOfZion/neo-go/pkg/io"
|
"github.com/CityOfZion/neo-go/pkg/io"
|
||||||
|
@ -184,7 +184,7 @@ func (m *Message) decodePayload(br *io.BinReader) error {
|
||||||
case CMDAddr:
|
case CMDAddr:
|
||||||
p = &payload.AddressList{}
|
p = &payload.AddressList{}
|
||||||
case CMDBlock:
|
case CMDBlock:
|
||||||
p = &core.Block{}
|
p = &block.Block{}
|
||||||
case CMDConsensus:
|
case CMDConsensus:
|
||||||
p = &consensus.Payload{}
|
p = &consensus.Payload{}
|
||||||
case CMDGetBlocks:
|
case CMDGetBlocks:
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
package payload
|
package payload
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/CityOfZion/neo-go/pkg/core"
|
"github.com/CityOfZion/neo-go/pkg/core/block"
|
||||||
"github.com/CityOfZion/neo-go/pkg/io"
|
"github.com/CityOfZion/neo-go/pkg/io"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Headers payload.
|
// Headers payload.
|
||||||
type Headers struct {
|
type Headers struct {
|
||||||
Hdrs []*core.Header
|
Hdrs []*block.Header
|
||||||
}
|
}
|
||||||
|
|
||||||
// Users can at most request 2k header.
|
// Users can at most request 2k header.
|
||||||
|
@ -30,10 +30,10 @@ func (p *Headers) DecodeBinary(br *io.BinReader) {
|
||||||
lenHeaders = MaxHeadersAllowed
|
lenHeaders = MaxHeadersAllowed
|
||||||
}
|
}
|
||||||
|
|
||||||
p.Hdrs = make([]*core.Header, lenHeaders)
|
p.Hdrs = make([]*block.Header, lenHeaders)
|
||||||
|
|
||||||
for i := 0; i < int(lenHeaders); i++ {
|
for i := 0; i < int(lenHeaders); i++ {
|
||||||
header := &core.Header{}
|
header := &block.Header{}
|
||||||
header.DecodeBinary(br)
|
header.DecodeBinary(br)
|
||||||
p.Hdrs[i] = header
|
p.Hdrs[i] = header
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ import (
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/CityOfZion/neo-go/pkg/core"
|
"github.com/CityOfZion/neo-go/pkg/core/block"
|
||||||
"github.com/CityOfZion/neo-go/pkg/core/transaction"
|
"github.com/CityOfZion/neo-go/pkg/core/transaction"
|
||||||
"github.com/CityOfZion/neo-go/pkg/io"
|
"github.com/CityOfZion/neo-go/pkg/io"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
@ -26,11 +26,11 @@ func TestHeadersEncodeDecode(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTestHeaders(n int) *Headers {
|
func newTestHeaders(n int) *Headers {
|
||||||
headers := &Headers{Hdrs: make([]*core.Header, n)}
|
headers := &Headers{Hdrs: make([]*block.Header, n)}
|
||||||
|
|
||||||
for i := range headers.Hdrs {
|
for i := range headers.Hdrs {
|
||||||
headers.Hdrs[i] = &core.Header{
|
headers.Hdrs[i] = &block.Header{
|
||||||
BlockBase: core.BlockBase{
|
Base: block.Base{
|
||||||
Index: uint32(i + 1),
|
Index: uint32(i + 1),
|
||||||
Script: transaction.Witness{
|
Script: transaction.Witness{
|
||||||
InvocationScript: []byte{0x0},
|
InvocationScript: []byte{0x0},
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
package payload
|
package payload
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/CityOfZion/neo-go/pkg/core"
|
"github.com/CityOfZion/neo-go/pkg/core/block"
|
||||||
"github.com/CityOfZion/neo-go/pkg/io"
|
"github.com/CityOfZion/neo-go/pkg/io"
|
||||||
"github.com/CityOfZion/neo-go/pkg/util"
|
"github.com/CityOfZion/neo-go/pkg/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MerkleBlock represents a merkle block packet payload.
|
// MerkleBlock represents a merkle block packet payload.
|
||||||
type MerkleBlock struct {
|
type MerkleBlock struct {
|
||||||
*core.BlockBase
|
*block.Base
|
||||||
TxCount int
|
TxCount int
|
||||||
Hashes []util.Uint256
|
Hashes []util.Uint256
|
||||||
Flags []byte
|
Flags []byte
|
||||||
|
@ -16,8 +16,8 @@ type MerkleBlock struct {
|
||||||
|
|
||||||
// DecodeBinary implements Serializable interface.
|
// DecodeBinary implements Serializable interface.
|
||||||
func (m *MerkleBlock) DecodeBinary(br *io.BinReader) {
|
func (m *MerkleBlock) DecodeBinary(br *io.BinReader) {
|
||||||
m.BlockBase = &core.BlockBase{}
|
m.Base = &block.Base{}
|
||||||
m.BlockBase.DecodeBinary(br)
|
m.Base.DecodeBinary(br)
|
||||||
|
|
||||||
m.TxCount = int(br.ReadVarUint())
|
m.TxCount = int(br.ReadVarUint())
|
||||||
br.ReadArray(&m.Hashes)
|
br.ReadArray(&m.Hashes)
|
||||||
|
@ -26,8 +26,8 @@ func (m *MerkleBlock) DecodeBinary(br *io.BinReader) {
|
||||||
|
|
||||||
// EncodeBinary implements Serializable interface.
|
// EncodeBinary implements Serializable interface.
|
||||||
func (m *MerkleBlock) EncodeBinary(bw *io.BinWriter) {
|
func (m *MerkleBlock) EncodeBinary(bw *io.BinWriter) {
|
||||||
m.BlockBase = &core.BlockBase{}
|
m.Base = &block.Base{}
|
||||||
m.BlockBase.EncodeBinary(bw)
|
m.Base.EncodeBinary(bw)
|
||||||
|
|
||||||
bw.WriteVarUint(uint64(m.TxCount))
|
bw.WriteVarUint(uint64(m.TxCount))
|
||||||
bw.WriteArray(m.Hashes)
|
bw.WriteArray(m.Hashes)
|
||||||
|
|
|
@ -12,6 +12,8 @@ import (
|
||||||
|
|
||||||
"github.com/CityOfZion/neo-go/pkg/consensus"
|
"github.com/CityOfZion/neo-go/pkg/consensus"
|
||||||
"github.com/CityOfZion/neo-go/pkg/core"
|
"github.com/CityOfZion/neo-go/pkg/core"
|
||||||
|
"github.com/CityOfZion/neo-go/pkg/core/block"
|
||||||
|
"github.com/CityOfZion/neo-go/pkg/core/mempool"
|
||||||
"github.com/CityOfZion/neo-go/pkg/core/transaction"
|
"github.com/CityOfZion/neo-go/pkg/core/transaction"
|
||||||
"github.com/CityOfZion/neo-go/pkg/network/payload"
|
"github.com/CityOfZion/neo-go/pkg/network/payload"
|
||||||
"github.com/CityOfZion/neo-go/pkg/util"
|
"github.com/CityOfZion/neo-go/pkg/util"
|
||||||
|
@ -421,7 +423,7 @@ func (s *Server) handleHeadersCmd(p Peer, headers *payload.Headers) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// handleBlockCmd processes the received block received from its peer.
|
// handleBlockCmd processes the received block received from its peer.
|
||||||
func (s *Server) handleBlockCmd(p Peer, block *core.Block) error {
|
func (s *Server) handleBlockCmd(p Peer, block *block.Block) error {
|
||||||
return s.bQueue.putBlock(block)
|
return s.bQueue.putBlock(block)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -545,7 +547,7 @@ func (s *Server) handleGetHeadersCmd(p Peer, gh *payload.GetBlocks) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
resp := payload.Headers{}
|
resp := payload.Headers{}
|
||||||
resp.Hdrs = make([]*core.Header, 0, payload.MaxHeadersAllowed)
|
resp.Hdrs = make([]*block.Header, 0, payload.MaxHeadersAllowed)
|
||||||
for i := start.Index + 1; i < start.Index+1+payload.MaxHeadersAllowed; i++ {
|
for i := start.Index + 1; i < start.Index+1+payload.MaxHeadersAllowed; i++ {
|
||||||
hash := s.chain.GetHeaderHash(int(i))
|
hash := s.chain.GetHeaderHash(int(i))
|
||||||
if hash.Equals(util.Uint256{}) || hash.Equals(gh.HashStop) {
|
if hash.Equals(util.Uint256{}) || hash.Equals(gh.HashStop) {
|
||||||
|
@ -672,7 +674,7 @@ func (s *Server) handleMessage(peer Peer, msg *Message) error {
|
||||||
inventory := msg.Payload.(*payload.Inventory)
|
inventory := msg.Payload.(*payload.Inventory)
|
||||||
return s.handleInvCmd(peer, inventory)
|
return s.handleInvCmd(peer, inventory)
|
||||||
case CMDBlock:
|
case CMDBlock:
|
||||||
block := msg.Payload.(*core.Block)
|
block := msg.Payload.(*block.Block)
|
||||||
return s.handleBlockCmd(peer, block)
|
return s.handleBlockCmd(peer, block)
|
||||||
case CMDConsensus:
|
case CMDConsensus:
|
||||||
cp := msg.Payload.(*consensus.Payload)
|
cp := msg.Payload.(*consensus.Payload)
|
||||||
|
@ -735,7 +737,7 @@ func (s *Server) relayInventoryCmd(cmd CommandType, t payload.InventoryType, has
|
||||||
}
|
}
|
||||||
|
|
||||||
// relayBlock tells all the other connected nodes about the given block.
|
// relayBlock tells all the other connected nodes about the given block.
|
||||||
func (s *Server) relayBlock(b *core.Block) {
|
func (s *Server) relayBlock(b *block.Block) {
|
||||||
s.relayInventoryCmd(CMDInv, payload.BlockType, b.Hash())
|
s.relayInventoryCmd(CMDInv, payload.BlockType, b.Hash())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -754,7 +756,7 @@ func (s *Server) RelayTxn(t *transaction.Transaction) RelayReason {
|
||||||
// TODO: Implement Plugin.CheckPolicy?
|
// TODO: Implement Plugin.CheckPolicy?
|
||||||
//if (!Plugin.CheckPolicy(transaction))
|
//if (!Plugin.CheckPolicy(transaction))
|
||||||
// return RelayResultReason.PolicyFail;
|
// return RelayResultReason.PolicyFail;
|
||||||
if ok := s.chain.GetMemPool().TryAdd(t.Hash(), core.NewPoolItem(t, s.chain)); !ok {
|
if ok := s.chain.GetMemPool().TryAdd(t.Hash(), mempool.NewPoolItem(t, s.chain)); !ok {
|
||||||
return RelayOutOfMemory
|
return RelayOutOfMemory
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
|
|
||||||
"github.com/CityOfZion/neo-go/config"
|
"github.com/CityOfZion/neo-go/config"
|
||||||
"github.com/CityOfZion/neo-go/pkg/core"
|
"github.com/CityOfZion/neo-go/pkg/core"
|
||||||
|
"github.com/CityOfZion/neo-go/pkg/core/block"
|
||||||
"github.com/CityOfZion/neo-go/pkg/core/storage"
|
"github.com/CityOfZion/neo-go/pkg/core/storage"
|
||||||
"github.com/CityOfZion/neo-go/pkg/io"
|
"github.com/CityOfZion/neo-go/pkg/io"
|
||||||
"github.com/CityOfZion/neo-go/pkg/network"
|
"github.com/CityOfZion/neo-go/pkg/network"
|
||||||
|
@ -193,10 +194,10 @@ func initServerWithInMemoryChain(t *testing.T) (*core.Blockchain, http.HandlerFu
|
||||||
nBlocks = br.ReadU32LE()
|
nBlocks = br.ReadU32LE()
|
||||||
require.Nil(t, br.Err)
|
require.Nil(t, br.Err)
|
||||||
for i := 0; i < int(nBlocks); i++ {
|
for i := 0; i < int(nBlocks); i++ {
|
||||||
block := &core.Block{}
|
b := &block.Block{}
|
||||||
block.DecodeBinary(br)
|
b.DecodeBinary(br)
|
||||||
require.Nil(t, br.Err)
|
require.Nil(t, br.Err)
|
||||||
require.NoError(t, chain.AddBlock(block))
|
require.NoError(t, chain.AddBlock(b))
|
||||||
}
|
}
|
||||||
|
|
||||||
serverConfig := network.NewServerConfig(cfg)
|
serverConfig := network.NewServerConfig(cfg)
|
||||||
|
|
|
@ -2,14 +2,15 @@ package wrappers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/CityOfZion/neo-go/pkg/core"
|
"github.com/CityOfZion/neo-go/pkg/core"
|
||||||
|
"github.com/CityOfZion/neo-go/pkg/core/block"
|
||||||
"github.com/CityOfZion/neo-go/pkg/util"
|
"github.com/CityOfZion/neo-go/pkg/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
// Block wrapper used for the representation of
|
// Block wrapper used for the representation of
|
||||||
// core.Block / core.BlockBase on the RPC Server.
|
// block.Block / block.Base on the RPC Server.
|
||||||
Block struct {
|
Block struct {
|
||||||
*core.Block
|
*block.Block
|
||||||
Confirmations uint32 `json:"confirmations"`
|
Confirmations uint32 `json:"confirmations"`
|
||||||
NextBlockHash util.Uint256 `json:"nextblockhash,omitempty"`
|
NextBlockHash util.Uint256 `json:"nextblockhash,omitempty"`
|
||||||
Hash util.Uint256 `json:"hash"`
|
Hash util.Uint256 `json:"hash"`
|
||||||
|
@ -17,7 +18,7 @@ type (
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewBlock creates a new Block wrapper.
|
// NewBlock creates a new Block wrapper.
|
||||||
func NewBlock(block *core.Block, chain core.Blockchainer) Block {
|
func NewBlock(block *block.Block, chain core.Blockchainer) Block {
|
||||||
blockWrapper := Block{
|
blockWrapper := Block{
|
||||||
Block: block,
|
Block: block,
|
||||||
Hash: block.Hash(),
|
Hash: block.Hash(),
|
||||||
|
|
|
@ -2,6 +2,7 @@ package wrappers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/CityOfZion/neo-go/pkg/core"
|
"github.com/CityOfZion/neo-go/pkg/core"
|
||||||
|
"github.com/CityOfZion/neo-go/pkg/core/block"
|
||||||
"github.com/CityOfZion/neo-go/pkg/core/transaction"
|
"github.com/CityOfZion/neo-go/pkg/core/transaction"
|
||||||
"github.com/CityOfZion/neo-go/pkg/io"
|
"github.com/CityOfZion/neo-go/pkg/io"
|
||||||
"github.com/CityOfZion/neo-go/pkg/util"
|
"github.com/CityOfZion/neo-go/pkg/util"
|
||||||
|
@ -21,9 +22,9 @@ type TransactionOutputRaw struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewTransactionOutputRaw returns a new ransactionOutputRaw object.
|
// NewTransactionOutputRaw returns a new ransactionOutputRaw object.
|
||||||
func NewTransactionOutputRaw(tx *transaction.Transaction, header *core.Header, chain core.Blockchainer) TransactionOutputRaw {
|
func NewTransactionOutputRaw(tx *transaction.Transaction, header *block.Header, chain core.Blockchainer) TransactionOutputRaw {
|
||||||
// confirmations formula
|
// confirmations formula
|
||||||
confirmations := int(chain.BlockHeight() - header.BlockBase.Index + 1)
|
confirmations := int(chain.BlockHeight() - header.Base.Index + 1)
|
||||||
// set index position
|
// set index position
|
||||||
for i, o := range tx.Outputs {
|
for i, o := range tx.Outputs {
|
||||||
o.Position = i
|
o.Position = i
|
||||||
|
|
Loading…
Reference in a new issue