mirror of
https://github.com/kaspanet/kaspad.git
synced 2026-02-21 11:17:05 +00:00
Compare commits
63 Commits
v0.6.0-dev
...
v0.6.8-dev
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a32a9011c7 | ||
|
|
5da957f16e | ||
|
|
505d264603 | ||
|
|
883361fea3 | ||
|
|
13a6872a45 | ||
|
|
c82a951a24 | ||
|
|
bbb9dfa4cd | ||
|
|
86d51fa1cb | ||
|
|
8dd7b95423 | ||
|
|
b668d98942 | ||
|
|
e9602cc777 | ||
|
|
5fd164bf66 | ||
|
|
83e7c9e8e4 | ||
|
|
a6b8eea369 | ||
|
|
15b545ee2b | ||
|
|
667b2d46e9 | ||
|
|
53ab906ea8 | ||
|
|
5d20772f94 | ||
|
|
d4728bd9b6 | ||
|
|
4dbd64478c | ||
|
|
7756baf9a9 | ||
|
|
c331293a2e | ||
|
|
fcae491e6d | ||
|
|
5a4cafe342 | ||
|
|
8dae378bd9 | ||
|
|
8dd409dc1c | ||
|
|
74110a2e49 | ||
|
|
ce876a7c44 | ||
|
|
d14809694f | ||
|
|
450ff81f86 | ||
|
|
1f04f30ea7 | ||
|
|
3e4e8d8b6b | ||
|
|
31c0399484 | ||
|
|
8cac582f6d | ||
|
|
f2a3ccd9ab | ||
|
|
31b5cd8d28 | ||
|
|
96bd1fa99b | ||
|
|
48d498e820 | ||
|
|
32c5cfeaf5 | ||
|
|
d55f4e8164 | ||
|
|
1927e81202 | ||
|
|
8a4ece1101 | ||
|
|
0bf1052abf | ||
|
|
2af03c1ccf | ||
|
|
a2aa58c8a4 | ||
|
|
7e74fc0b2b | ||
|
|
0653e59e16 | ||
|
|
32463ce906 | ||
|
|
23a3594c18 | ||
|
|
ffe153efa7 | ||
|
|
ca3172dad0 | ||
|
|
22dc3f998f | ||
|
|
91f4ed9825 | ||
|
|
aa9556aa59 | ||
|
|
91f0fe5740 | ||
|
|
b0fecc9f87 | ||
|
|
53cccd405f | ||
|
|
5b84184921 | ||
|
|
af1df425a2 | ||
|
|
8e170cf327 | ||
|
|
b55cfee8c8 | ||
|
|
420c3d4258 | ||
|
|
b92943a98c |
@@ -40,10 +40,8 @@ recommended that `GOPATH` is set to a directory in your home directory such as
|
||||
```bash
|
||||
$ git clone https://github.com/kaspanet/kaspad $GOPATH/src/github.com/kaspanet/kaspad
|
||||
$ cd $GOPATH/src/github.com/kaspanet/kaspad
|
||||
$ ./test.sh
|
||||
$ go install . ./cmd/...
|
||||
```
|
||||
`./test.sh` tests can be skipped, but some things might not run correctly on your system if tests fail.
|
||||
|
||||
- Kaspad (and utilities) should now be installed in `$GOPATH/bin`. If you did
|
||||
not already add the bin directory to your system path during Go installation,
|
||||
|
||||
68
app/app.go
68
app/app.go
@@ -4,26 +4,26 @@ import (
|
||||
"fmt"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/kaspanet/kaspad/addressmanager"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/addressmanager"
|
||||
|
||||
"github.com/kaspanet/kaspad/netadapter/id"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/id"
|
||||
|
||||
"github.com/kaspanet/kaspad/blockdag"
|
||||
"github.com/kaspanet/kaspad/blockdag/indexers"
|
||||
"github.com/kaspanet/kaspad/config"
|
||||
"github.com/kaspanet/kaspad/connmanager"
|
||||
"github.com/kaspanet/kaspad/dbaccess"
|
||||
"github.com/kaspanet/kaspad/dnsseed"
|
||||
"github.com/kaspanet/kaspad/mempool"
|
||||
"github.com/kaspanet/kaspad/mining"
|
||||
"github.com/kaspanet/kaspad/netadapter"
|
||||
"github.com/kaspanet/kaspad/protocol"
|
||||
"github.com/kaspanet/kaspad/rpc"
|
||||
"github.com/kaspanet/kaspad/signal"
|
||||
"github.com/kaspanet/kaspad/txscript"
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
"github.com/kaspanet/kaspad/app/protocol"
|
||||
"github.com/kaspanet/kaspad/domain/blockdag"
|
||||
"github.com/kaspanet/kaspad/domain/blockdag/indexers"
|
||||
"github.com/kaspanet/kaspad/domain/mempool"
|
||||
"github.com/kaspanet/kaspad/domain/mining"
|
||||
"github.com/kaspanet/kaspad/domain/txscript"
|
||||
"github.com/kaspanet/kaspad/infrastructure/config"
|
||||
"github.com/kaspanet/kaspad/infrastructure/db/dbaccess"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/connmanager"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/dnsseed"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/rpc"
|
||||
"github.com/kaspanet/kaspad/infrastructure/os/signal"
|
||||
"github.com/kaspanet/kaspad/util"
|
||||
"github.com/kaspanet/kaspad/util/panics"
|
||||
"github.com/kaspanet/kaspad/wire"
|
||||
)
|
||||
|
||||
// App is a wrapper for all the kaspad services
|
||||
@@ -62,11 +62,11 @@ func (a *App) Start() {
|
||||
}
|
||||
|
||||
// Stop gracefully shuts down all the kaspad services.
|
||||
func (a *App) Stop() error {
|
||||
func (a *App) Stop() {
|
||||
// Make sure this only happens once.
|
||||
if atomic.AddInt32(&a.shutdown, 1) != 1 {
|
||||
log.Infof("Kaspad is already in the process of shutting down")
|
||||
return nil
|
||||
return
|
||||
}
|
||||
|
||||
log.Warnf("Kaspad shutting down")
|
||||
@@ -86,7 +86,12 @@ func (a *App) Stop() error {
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
err = a.addressManager.Stop()
|
||||
if err != nil {
|
||||
log.Errorf("Error stopping address manager: %s", err)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// New returns a new App instance configured to listen on addr for the
|
||||
@@ -109,13 +114,14 @@ func New(cfg *config.Config, databaseContext *dbaccess.DatabaseContext, interrup
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
addressManager := addressmanager.New(cfg, databaseContext)
|
||||
|
||||
addressManager, err := addressmanager.New(cfg, databaseContext)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
connectionManager, err := connmanager.New(cfg, netAdapter, addressManager)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
protocolManager, err := protocol.NewManager(cfg, dag, netAdapter, addressManager, txMempool, connectionManager)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -138,8 +144,8 @@ func New(cfg *config.Config, databaseContext *dbaccess.DatabaseContext, interrup
|
||||
|
||||
func (a *App) maybeSeedFromDNS() {
|
||||
if !a.cfg.DisableDNSSeed {
|
||||
dnsseed.SeedFromDNS(a.cfg.NetParams(), a.cfg.DNSSeed, wire.SFNodeNetwork, false, nil,
|
||||
a.cfg.Lookup, func(addresses []*wire.NetAddress) {
|
||||
dnsseed.SeedFromDNS(a.cfg.NetParams(), a.cfg.DNSSeed, appmessage.SFNodeNetwork, false, nil,
|
||||
a.cfg.Lookup, func(addresses []*appmessage.NetAddress) {
|
||||
// Kaspad uses a lookup of the dns seeder here. Since seeder returns
|
||||
// IPs of nodes and not its own IP, we can not know real IP of
|
||||
// source. So we'll take first returned address as source.
|
||||
@@ -168,6 +174,7 @@ func setupIndexes(cfg *config.Config) (blockdag.IndexManager, *indexers.Acceptan
|
||||
var acceptanceIndex *indexers.AcceptanceIndex
|
||||
if cfg.AcceptanceIndex {
|
||||
log.Info("acceptance index is enabled")
|
||||
acceptanceIndex = indexers.NewAcceptanceIndex()
|
||||
indexes = append(indexes, acceptanceIndex)
|
||||
}
|
||||
|
||||
@@ -189,11 +196,10 @@ func setupMempool(cfg *config.Config, dag *blockdag.BlockDAG, sigCache *txscript
|
||||
MaxTxVersion: 1,
|
||||
},
|
||||
CalcSequenceLockNoLock: func(tx *util.Tx, utxoSet blockdag.UTXOSet) (*blockdag.SequenceLock, error) {
|
||||
return dag.CalcSequenceLockNoLock(tx, utxoSet, true)
|
||||
return dag.CalcSequenceLockNoLock(tx, utxoSet)
|
||||
},
|
||||
IsDeploymentActive: dag.IsDeploymentActive,
|
||||
SigCache: sigCache,
|
||||
DAG: dag,
|
||||
SigCache: sigCache,
|
||||
DAG: dag,
|
||||
}
|
||||
|
||||
return mempool.New(&mempoolConfig)
|
||||
@@ -240,9 +246,3 @@ func (a *App) P2PNodeID() *id.ID {
|
||||
func (a *App) AddressManager() *addressmanager.AddressManager {
|
||||
return a.addressManager
|
||||
}
|
||||
|
||||
// WaitForShutdown blocks until the main listener and peer handlers are stopped.
|
||||
func (a *App) WaitForShutdown() {
|
||||
// TODO(libp2p)
|
||||
// a.p2pServer.WaitForShutdown()
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ to a remote node running a kaspa peer. Example syntax is:
|
||||
|
||||
// Reads and validates the next kaspa message from conn using the
|
||||
// protocol version pver and the kaspa network kaspanet. The returns
|
||||
// are a wire.Message, a []byte which contains the unmarshalled
|
||||
// are a appmessage.Message, a []byte which contains the unmarshalled
|
||||
// raw payload, and a possible error.
|
||||
msg, rawPayload, err := wire.ReadMessage(conn, pver, kaspanet)
|
||||
if err != nil {
|
||||
24
app/appmessage/base_message.go
Normal file
24
app/appmessage/base_message.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package appmessage
|
||||
|
||||
import "time"
|
||||
|
||||
type baseMessage struct {
|
||||
messageNumber uint64
|
||||
receivedAt time.Time
|
||||
}
|
||||
|
||||
func (b *baseMessage) MessageNumber() uint64 {
|
||||
return b.messageNumber
|
||||
}
|
||||
|
||||
func (b *baseMessage) SetMessageNumber(messageNumber uint64) {
|
||||
b.messageNumber = messageNumber
|
||||
}
|
||||
|
||||
func (b *baseMessage) ReceivedAt() time.Time {
|
||||
return b.receivedAt
|
||||
}
|
||||
|
||||
func (b *baseMessage) SetReceivedAt(receivedAt time.Time) {
|
||||
b.receivedAt = receivedAt
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package wire
|
||||
package appmessage
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@@ -16,7 +16,7 @@ import (
|
||||
)
|
||||
|
||||
// genesisCoinbaseTx is the coinbase transaction for the genesis blocks for
|
||||
// the main network, regression test network, and test network.
|
||||
// the main network and test network.
|
||||
var genesisCoinbaseTxIns = []*TxIn{
|
||||
{
|
||||
PreviousOutpoint: Outpoint{
|
||||
@@ -352,7 +352,7 @@ func BenchmarkReadBlockHeader(b *testing.B) {
|
||||
0x3a, 0x9f, 0xb8, 0xaa, 0x4b, 0x1e, 0x5e, 0x4a, // MerkleRoot
|
||||
0x29, 0xab, 0x5f, 0x49, 0x00, 0x00, 0x00, 0x00, // Timestamp
|
||||
0xff, 0xff, 0x00, 0x1d, // Bits
|
||||
0xf3, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, // Fake Nonce. TODO: (Ori) Replace to a real nonce
|
||||
0xf3, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, // Fake Nonce
|
||||
0x00, // TxnCount Varint
|
||||
}
|
||||
r := bytes.NewReader(buf)
|
||||
@@ -411,3 +411,21 @@ func BenchmarkDoubleHashH(b *testing.B) {
|
||||
_ = daghash.DoubleHashH(txBytes)
|
||||
}
|
||||
}
|
||||
|
||||
// BenchmarkDoubleHashWriter performs a benchmark on how long it takes to perform
|
||||
// a double hash via the writer returning a daghash.Hash.
|
||||
func BenchmarkDoubleHashWriter(b *testing.B) {
|
||||
var buf bytes.Buffer
|
||||
err := genesisCoinbaseTx.Serialize(&buf)
|
||||
if err != nil {
|
||||
b.Fatalf("Serialize: unexpected error: %+v", err)
|
||||
}
|
||||
txBytes := buf.Bytes()
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
writer := daghash.NewDoubleHashWriter()
|
||||
_, _ = writer.Write(txBytes)
|
||||
writer.Finalize()
|
||||
}
|
||||
}
|
||||
@@ -2,13 +2,14 @@
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package wire
|
||||
package appmessage
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/kaspanet/kaspad/util/daghash"
|
||||
"github.com/kaspanet/kaspad/util/mstime"
|
||||
"io"
|
||||
)
|
||||
|
||||
// BaseBlockHeaderPayload is the base number of bytes a block header can be,
|
||||
@@ -65,13 +66,18 @@ func (h *BlockHeader) NumParentBlocks() byte {
|
||||
// BlockHash computes the block identifier hash for the given block header.
|
||||
func (h *BlockHeader) BlockHash() *daghash.Hash {
|
||||
// Encode the header and double sha256 everything prior to the number of
|
||||
// transactions. Ignore the error returns since there is no way the
|
||||
// encode could fail except being out of memory which would cause a
|
||||
// run-time panic.
|
||||
buf := bytes.NewBuffer(make([]byte, 0, BaseBlockHeaderPayload+h.NumParentBlocks()))
|
||||
_ = writeBlockHeader(buf, 0, h)
|
||||
// transactions.
|
||||
writer := daghash.NewDoubleHashWriter()
|
||||
err := writeBlockHeader(writer, 0, h)
|
||||
if err != nil {
|
||||
// It seems like this could only happen if the writer returned an error.
|
||||
// and this writer should never return an error (no allocations or possible failures)
|
||||
// the only non-writer error path here is unknown types in `WriteElement`
|
||||
panic(fmt.Sprintf("BlockHash() failed. this should never fail unless BlockHeader was changed. err: %+v", err))
|
||||
}
|
||||
|
||||
return daghash.DoubleHashP(buf.Bytes())
|
||||
res := writer.Finalize()
|
||||
return &res
|
||||
}
|
||||
|
||||
// IsGenesis returns true iff this block is a genesis block
|
||||
@@ -82,7 +88,7 @@ func (h *BlockHeader) IsGenesis() bool {
|
||||
// KaspaDecode decodes r using the kaspa protocol encoding into the receiver.
|
||||
// This is part of the Message interface implementation.
|
||||
// See Deserialize for decoding block headers stored to disk, such as in a
|
||||
// database, as opposed to decoding block headers from the wire.
|
||||
// database, as opposed to decoding block headers from the appmessage.
|
||||
func (h *BlockHeader) KaspaDecode(r io.Reader, pver uint32) error {
|
||||
return readBlockHeader(r, pver, h)
|
||||
}
|
||||
@@ -90,7 +96,7 @@ func (h *BlockHeader) KaspaDecode(r io.Reader, pver uint32) error {
|
||||
// KaspaEncode encodes the receiver to w using the kaspa protocol encoding.
|
||||
// This is part of the Message interface implementation.
|
||||
// See Serialize for encoding block headers to be stored to disk, such as in a
|
||||
// database, as opposed to encoding block headers for the wire.
|
||||
// database, as opposed to encoding block headers for the appmessage.
|
||||
func (h *BlockHeader) KaspaEncode(w io.Writer, pver uint32) error {
|
||||
return writeBlockHeader(w, pver, h)
|
||||
}
|
||||
@@ -99,7 +105,7 @@ func (h *BlockHeader) KaspaEncode(w io.Writer, pver uint32) error {
|
||||
// that is suitable for long-term storage such as a database while respecting
|
||||
// the Version field.
|
||||
func (h *BlockHeader) Deserialize(r io.Reader) error {
|
||||
// At the current time, there is no difference between the wire encoding
|
||||
// At the current time, there is no difference between the appmessage encoding
|
||||
// at protocol version 0 and the stable long-term storage format. As
|
||||
// a result, make use of readBlockHeader.
|
||||
return readBlockHeader(r, 0, h)
|
||||
@@ -109,7 +115,7 @@ func (h *BlockHeader) Deserialize(r io.Reader) error {
|
||||
// that is suitable for long-term storage such as a database while respecting
|
||||
// the Version field.
|
||||
func (h *BlockHeader) Serialize(w io.Writer) error {
|
||||
// At the current time, there is no difference between the wire encoding
|
||||
// At the current time, there is no difference between the appmessage encoding
|
||||
// at protocol version 0 and the stable long-term storage format. As
|
||||
// a result, make use of writeBlockHeader.
|
||||
return writeBlockHeader(w, 0, h)
|
||||
@@ -143,7 +149,7 @@ func NewBlockHeader(version int32, parentHashes []*daghash.Hash, hashMerkleRoot
|
||||
|
||||
// readBlockHeader reads a kaspa block header from r. See Deserialize for
|
||||
// decoding block headers stored to disk, such as in a database, as opposed to
|
||||
// decoding from the wire.
|
||||
// decoding from the appmessage.
|
||||
func readBlockHeader(r io.Reader, pver uint32, bh *BlockHeader) error {
|
||||
var numParentBlocks byte
|
||||
err := readElements(r, &bh.Version, &numParentBlocks)
|
||||
@@ -169,7 +175,7 @@ func readBlockHeader(r io.Reader, pver uint32, bh *BlockHeader) error {
|
||||
|
||||
// writeBlockHeader writes a kaspa block header to w. See Serialize for
|
||||
// encoding block headers to be stored to disk, such as in a database, as
|
||||
// opposed to encoding for the wire.
|
||||
// opposed to encoding for the appmessage.
|
||||
func writeBlockHeader(w io.Writer, pver uint32, bh *BlockHeader) error {
|
||||
timestamp := bh.Timestamp.UnixMilliseconds()
|
||||
if err := writeElements(w, bh.Version, bh.NumParentBlocks()); err != nil {
|
||||
@@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package wire
|
||||
package appmessage
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@@ -47,9 +47,9 @@ func TestBlockHeader(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestBlockHeaderWire tests the BlockHeader wire encode and decode for various
|
||||
// TestBlockHeaderEncoding tests the BlockHeader appmessage encode and decode for various
|
||||
// protocol versions.
|
||||
func TestBlockHeaderWire(t *testing.T) {
|
||||
func TestBlockHeaderEncoding(t *testing.T) {
|
||||
nonce := uint64(123123) // 0x000000000001e0f3
|
||||
pver := ProtocolVersion
|
||||
|
||||
@@ -66,7 +66,7 @@ func TestBlockHeaderWire(t *testing.T) {
|
||||
Nonce: nonce,
|
||||
}
|
||||
|
||||
// baseBlockHdrEncoded is the wire encoded bytes of baseBlockHdr.
|
||||
// baseBlockHdrEncoded is the appmessage encoded bytes of baseBlockHdr.
|
||||
baseBlockHdrEncoded := []byte{
|
||||
0x01, 0x00, 0x00, 0x00, // Version 1
|
||||
0x02, // NumParentBlocks
|
||||
@@ -92,14 +92,14 @@ func TestBlockHeaderWire(t *testing.T) {
|
||||
0x65, 0x9C, 0x79, 0x3C, 0xE3, 0x70, 0xD9, 0x5F,
|
||||
0x99, 0x0f, 0xed, 0x15, 0x73, 0x01, 0x00, 0x00, // Timestamp
|
||||
0xff, 0xff, 0x00, 0x1d, // Bits
|
||||
0xf3, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, // Fake Nonce. TODO: (Ori) Replace to a real nonce
|
||||
0xf3, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, // Fake Nonce
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
in *BlockHeader // Data to encode
|
||||
out *BlockHeader // Expected decoded data
|
||||
buf []byte // Wire encoding
|
||||
pver uint32 // Protocol version for wire encoding
|
||||
buf []byte // Encoded data
|
||||
pver uint32 // Protocol version for appmessage encoding
|
||||
}{
|
||||
// Latest protocol version.
|
||||
{
|
||||
@@ -112,7 +112,7 @@ func TestBlockHeaderWire(t *testing.T) {
|
||||
|
||||
t.Logf("Running %d tests", len(tests))
|
||||
for i, test := range tests {
|
||||
// Encode to wire format.
|
||||
// Encode to appmessage format.
|
||||
var buf bytes.Buffer
|
||||
err := writeBlockHeader(&buf, test.pver, test.in)
|
||||
if err != nil {
|
||||
@@ -137,7 +137,7 @@ func TestBlockHeaderWire(t *testing.T) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Decode the block header from wire format.
|
||||
// Decode the block header from appmessage format.
|
||||
var bh BlockHeader
|
||||
rbuf := bytes.NewReader(test.buf)
|
||||
err = readBlockHeader(rbuf, test.pver, &bh)
|
||||
@@ -182,7 +182,7 @@ func TestBlockHeaderSerialize(t *testing.T) {
|
||||
Nonce: nonce,
|
||||
}
|
||||
|
||||
// baseBlockHdrEncoded is the wire encoded bytes of baseBlockHdr.
|
||||
// baseBlockHdrEncoded is the appmessage encoded bytes of baseBlockHdr.
|
||||
baseBlockHdrEncoded := []byte{
|
||||
0x01, 0x00, 0x00, 0x00, // Version 1
|
||||
0x02, // NumParentBlocks
|
||||
@@ -208,7 +208,7 @@ func TestBlockHeaderSerialize(t *testing.T) {
|
||||
0x65, 0x9C, 0x79, 0x3C, 0xE3, 0x70, 0xD9, 0x5F,
|
||||
0x99, 0x0f, 0xed, 0x15, 0x73, 0x01, 0x00, 0x00, // Timestamp
|
||||
0xff, 0xff, 0x00, 0x1d, // Bits
|
||||
0xf3, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, // Fake Nonce. TODO: (Ori) Replace to a real nonce
|
||||
0xf3, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, // Fake Nonce
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
@@ -2,12 +2,12 @@
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package wire
|
||||
package appmessage
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"github.com/kaspanet/kaspad/netadapter/id"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/id"
|
||||
"github.com/kaspanet/kaspad/util/binaryserializer"
|
||||
"github.com/kaspanet/kaspad/util/daghash"
|
||||
"github.com/kaspanet/kaspad/util/mstime"
|
||||
@@ -20,6 +20,9 @@ import (
|
||||
// MaxVarIntPayload is the maximum payload size for a variable length integer.
|
||||
const MaxVarIntPayload = 9
|
||||
|
||||
// MaxInvPerMsg is the maximum number of inventory vectors that can be in any type of kaspa inv message.
|
||||
const MaxInvPerMsg = 1 << 17
|
||||
|
||||
var (
|
||||
// littleEndian is a convenience variable since binary.LittleEndian is
|
||||
// quite long.
|
||||
@@ -160,14 +163,6 @@ func ReadElement(r io.Reader, element interface{}) error {
|
||||
*e = ServiceFlag(rv)
|
||||
return nil
|
||||
|
||||
case *InvType:
|
||||
rv, err := binaryserializer.Uint32(r, littleEndian)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*e = InvType(rv)
|
||||
return nil
|
||||
|
||||
case *KaspaNet:
|
||||
rv, err := binaryserializer.Uint32(r, littleEndian)
|
||||
if err != nil {
|
||||
@@ -292,13 +287,6 @@ func WriteElement(w io.Writer, element interface{}) error {
|
||||
}
|
||||
return nil
|
||||
|
||||
case InvType:
|
||||
err := binaryserializer.PutUint32(w, littleEndian, uint32(e))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
|
||||
case KaspaNet:
|
||||
err := binaryserializer.PutUint32(w, littleEndian, uint32(e))
|
||||
if err != nil {
|
||||
@@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package wire
|
||||
package appmessage
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@@ -57,13 +57,13 @@ var exampleUTXOCommitment = &daghash.Hash{
|
||||
0x65, 0x9C, 0x79, 0x3C, 0xE3, 0x70, 0xD9, 0x5F,
|
||||
}
|
||||
|
||||
// TestElementWire tests wire encode and decode for various element types. This
|
||||
// TestElementEncoding tests appmessage encode and decode for various element types. This
|
||||
// is mainly to test the "fast" paths in readElement and writeElement which use
|
||||
// type assertions to avoid reflection when possible.
|
||||
func TestElementWire(t *testing.T) {
|
||||
func TestElementEncoding(t *testing.T) {
|
||||
tests := []struct {
|
||||
in interface{} // Value to encode
|
||||
buf []byte // Wire encoding
|
||||
buf []byte // Encoded value
|
||||
}{
|
||||
{int32(1), []byte{0x01, 0x00, 0x00, 0x00}},
|
||||
{uint32(256), []byte{0x00, 0x01, 0x00, 0x00}},
|
||||
@@ -121,10 +121,6 @@ func TestElementWire(t *testing.T) {
|
||||
ServiceFlag(SFNodeNetwork),
|
||||
[]byte{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
},
|
||||
{
|
||||
InvType(InvTypeTx),
|
||||
[]byte{0x01, 0x00, 0x00, 0x00},
|
||||
},
|
||||
{
|
||||
KaspaNet(Mainnet),
|
||||
[]byte{0x1d, 0xf7, 0xdc, 0x3d},
|
||||
@@ -133,7 +129,7 @@ func TestElementWire(t *testing.T) {
|
||||
|
||||
t.Logf("Running %d tests", len(tests))
|
||||
for i, test := range tests {
|
||||
// Write to wire format.
|
||||
// Write to appmessage format.
|
||||
var buf bytes.Buffer
|
||||
err := WriteElement(&buf, test.in)
|
||||
if err != nil {
|
||||
@@ -146,7 +142,7 @@ func TestElementWire(t *testing.T) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Read from wire format.
|
||||
// Read from appmessage format.
|
||||
rbuf := bytes.NewReader(test.buf)
|
||||
val := test.in
|
||||
if reflect.ValueOf(test.in).Kind() != reflect.Ptr {
|
||||
@@ -169,9 +165,9 @@ func TestElementWire(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestElementWireErrors performs negative tests against wire encode and decode
|
||||
// TestElementEncodingErrors performs negative tests against appmessage encode and decode
|
||||
// of various element types to confirm error paths work correctly.
|
||||
func TestElementWireErrors(t *testing.T) {
|
||||
func TestElementEncodingErrors(t *testing.T) {
|
||||
type writeElementReflect int32
|
||||
|
||||
tests := []struct {
|
||||
@@ -206,7 +202,6 @@ func TestElementWireErrors(t *testing.T) {
|
||||
0, io.ErrShortWrite, io.EOF,
|
||||
},
|
||||
{ServiceFlag(SFNodeNetwork), 0, io.ErrShortWrite, io.EOF},
|
||||
{InvType(InvTypeTx), 0, io.ErrShortWrite, io.EOF},
|
||||
{KaspaNet(Mainnet), 0, io.ErrShortWrite, io.EOF},
|
||||
// Type with no supported encoding.
|
||||
{writeElementReflect(0), 0, errNoEncodingForType, errNoEncodingForType},
|
||||
@@ -214,7 +209,7 @@ func TestElementWireErrors(t *testing.T) {
|
||||
|
||||
t.Logf("Running %d tests", len(tests))
|
||||
for i, test := range tests {
|
||||
// Encode to wire format.
|
||||
// Encode to appmessage format.
|
||||
w := newFixedWriter(test.max)
|
||||
err := WriteElement(w, test.in)
|
||||
if !errors.Is(err, test.writeErr) {
|
||||
@@ -223,7 +218,7 @@ func TestElementWireErrors(t *testing.T) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Decode from wire format.
|
||||
// Decode from appmessage format.
|
||||
r := newFixedReader(test.max, nil)
|
||||
val := test.in
|
||||
if reflect.ValueOf(test.in).Kind() != reflect.Ptr {
|
||||
@@ -238,11 +233,11 @@ func TestElementWireErrors(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestVarIntWire tests wire encode and decode for variable length integers.
|
||||
func TestVarIntWire(t *testing.T) {
|
||||
// TestVarIntEncoding tests appmessage encode and decode for variable length integers.
|
||||
func TestVarIntEncoding(t *testing.T) {
|
||||
tests := []struct {
|
||||
value uint64 // Value to encode
|
||||
buf []byte // Wire encoding
|
||||
buf []byte // Encoded value
|
||||
}{
|
||||
// Latest protocol version.
|
||||
// Single byte
|
||||
@@ -271,7 +266,7 @@ func TestVarIntWire(t *testing.T) {
|
||||
|
||||
t.Logf("Running %d tests", len(tests))
|
||||
for i, test := range tests {
|
||||
// Encode to wire format.
|
||||
// Encode to appmessage format.
|
||||
buf := &bytes.Buffer{}
|
||||
err := WriteVarInt(buf, test.value)
|
||||
if err != nil {
|
||||
@@ -284,7 +279,7 @@ func TestVarIntWire(t *testing.T) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Decode from wire format.
|
||||
// Decode from appmessage format.
|
||||
rbuf := bytes.NewReader(test.buf)
|
||||
val, err := ReadVarInt(rbuf)
|
||||
if err != nil {
|
||||
@@ -299,12 +294,12 @@ func TestVarIntWire(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestVarIntWireErrors performs negative tests against wire encode and decode
|
||||
// TestVarIntEncodingErrors performs negative tests against appmessage encode and decode
|
||||
// of variable length integers to confirm error paths work correctly.
|
||||
func TestVarIntWireErrors(t *testing.T) {
|
||||
func TestVarIntEncodingErrors(t *testing.T) {
|
||||
tests := []struct {
|
||||
in uint64 // Value to encode
|
||||
buf []byte // Wire encoding
|
||||
buf []byte // Encoded value
|
||||
max int // Max size of fixed buffer to induce errors
|
||||
writeErr error // Expected write error
|
||||
readErr error // Expected read error
|
||||
@@ -324,7 +319,7 @@ func TestVarIntWireErrors(t *testing.T) {
|
||||
|
||||
t.Logf("Running %d tests", len(tests))
|
||||
for i, test := range tests {
|
||||
// Encode to wire format.
|
||||
// Encode to appmessage format.
|
||||
w := newFixedWriter(test.max)
|
||||
err := WriteVarInt(w, test.in)
|
||||
if !errors.Is(err, test.writeErr) {
|
||||
@@ -333,7 +328,7 @@ func TestVarIntWireErrors(t *testing.T) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Decode from wire format.
|
||||
// Decode from appmessage format.
|
||||
r := newFixedReader(test.max, test.buf)
|
||||
_, err = ReadVarInt(r)
|
||||
if !errors.Is(err, test.readErr) {
|
||||
@@ -352,7 +347,7 @@ func TestVarIntNonCanonical(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string // Test name for easier identification
|
||||
in []byte // Value to decode
|
||||
pver uint32 // Protocol version for wire encoding
|
||||
pver uint32 // Protocol version for appmessage encoding
|
||||
}{
|
||||
{
|
||||
"0 encoded with 3 bytes", []byte{0xfd, 0x00, 0x00},
|
||||
@@ -384,7 +379,7 @@ func TestVarIntNonCanonical(t *testing.T) {
|
||||
|
||||
t.Logf("Running %d tests", len(tests))
|
||||
for i, test := range tests {
|
||||
// Decode from wire format.
|
||||
// Decode from appmessage format.
|
||||
rbuf := bytes.NewReader(test.in)
|
||||
val, err := ReadVarInt(rbuf)
|
||||
if msgErr := &(MessageError{}); !errors.As(err, &msgErr) {
|
||||
@@ -400,7 +395,7 @@ func TestVarIntNonCanonical(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestVarIntWire tests the serialize size for variable length integers.
|
||||
// TestVarIntEncoding tests the serialize size for variable length integers.
|
||||
func TestVarIntSerializeSize(t *testing.T) {
|
||||
tests := []struct {
|
||||
val uint64 // Value to get the serialized size for
|
||||
@@ -435,8 +430,8 @@ func TestVarIntSerializeSize(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestVarStringWire tests wire encode and decode for variable length strings.
|
||||
func TestVarStringWire(t *testing.T) {
|
||||
// TestVarStringEncoding tests appmessage encode and decode for variable length strings.
|
||||
func TestVarStringEncoding(t *testing.T) {
|
||||
pver := ProtocolVersion
|
||||
|
||||
// str256 is a string that takes a 2-byte varint to encode.
|
||||
@@ -445,8 +440,8 @@ func TestVarStringWire(t *testing.T) {
|
||||
tests := []struct {
|
||||
in string // String to encode
|
||||
out string // String to decoded value
|
||||
buf []byte // Wire encoding
|
||||
pver uint32 // Protocol version for wire encoding
|
||||
buf []byte // Encoded value
|
||||
pver uint32 // Protocol version for appmessage encoding
|
||||
}{
|
||||
// Latest protocol version.
|
||||
// Empty string
|
||||
@@ -459,7 +454,7 @@ func TestVarStringWire(t *testing.T) {
|
||||
|
||||
t.Logf("Running %d tests", len(tests))
|
||||
for i, test := range tests {
|
||||
// Encode to wire format.
|
||||
// Encode to appmessage format.
|
||||
var buf bytes.Buffer
|
||||
err := WriteVarString(&buf, test.in)
|
||||
if err != nil {
|
||||
@@ -472,7 +467,7 @@ func TestVarStringWire(t *testing.T) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Decode from wire format.
|
||||
// Decode from appmessage format.
|
||||
rbuf := bytes.NewReader(test.buf)
|
||||
val, err := ReadVarString(rbuf, test.pver)
|
||||
if err != nil {
|
||||
@@ -487,9 +482,9 @@ func TestVarStringWire(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestVarStringWireErrors performs negative tests against wire encode and
|
||||
// TestVarStringEncodingErrors performs negative tests against appmessage encode and
|
||||
// decode of variable length strings to confirm error paths work correctly.
|
||||
func TestVarStringWireErrors(t *testing.T) {
|
||||
func TestVarStringEncodingErrors(t *testing.T) {
|
||||
pver := ProtocolVersion
|
||||
|
||||
// str256 is a string that takes a 2-byte varint to encode.
|
||||
@@ -497,8 +492,8 @@ func TestVarStringWireErrors(t *testing.T) {
|
||||
|
||||
tests := []struct {
|
||||
in string // Value to encode
|
||||
buf []byte // Wire encoding
|
||||
pver uint32 // Protocol version for wire encoding
|
||||
buf []byte // Encoded value
|
||||
pver uint32 // Protocol version for appmessage encoding
|
||||
max int // Max size of fixed buffer to induce errors
|
||||
writeErr error // Expected write error
|
||||
readErr error // Expected read error
|
||||
@@ -514,7 +509,7 @@ func TestVarStringWireErrors(t *testing.T) {
|
||||
|
||||
t.Logf("Running %d tests", len(tests))
|
||||
for i, test := range tests {
|
||||
// Encode to wire format.
|
||||
// Encode to appmessage format.
|
||||
w := newFixedWriter(test.max)
|
||||
err := WriteVarString(w, test.in)
|
||||
if !errors.Is(err, test.writeErr) {
|
||||
@@ -523,7 +518,7 @@ func TestVarStringWireErrors(t *testing.T) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Decode from wire format.
|
||||
// Decode from appmessage format.
|
||||
r := newFixedReader(test.max, test.buf)
|
||||
_, err = ReadVarString(r, test.pver)
|
||||
if !errors.Is(err, test.readErr) {
|
||||
@@ -542,8 +537,8 @@ func TestVarStringOverflowErrors(t *testing.T) {
|
||||
pver := ProtocolVersion
|
||||
|
||||
tests := []struct {
|
||||
buf []byte // Wire encoding
|
||||
pver uint32 // Protocol version for wire encoding
|
||||
buf []byte // Encoded value
|
||||
pver uint32 // Protocol version for appmessage encoding
|
||||
err error // Expected error
|
||||
}{
|
||||
{[]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
|
||||
@@ -554,7 +549,7 @@ func TestVarStringOverflowErrors(t *testing.T) {
|
||||
|
||||
t.Logf("Running %d tests", len(tests))
|
||||
for i, test := range tests {
|
||||
// Decode from wire format.
|
||||
// Decode from appmessage format.
|
||||
rbuf := bytes.NewReader(test.buf)
|
||||
_, err := ReadVarString(rbuf, test.pver)
|
||||
if reflect.TypeOf(err) != reflect.TypeOf(test.err) {
|
||||
@@ -566,8 +561,8 @@ func TestVarStringOverflowErrors(t *testing.T) {
|
||||
|
||||
}
|
||||
|
||||
// TestVarBytesWire tests wire encode and decode for variable length byte array.
|
||||
func TestVarBytesWire(t *testing.T) {
|
||||
// TestVarBytesEncoding tests appmessage encode and decode for variable length byte array.
|
||||
func TestVarBytesEncoding(t *testing.T) {
|
||||
pver := ProtocolVersion
|
||||
|
||||
// bytes256 is a byte array that takes a 2-byte varint to encode.
|
||||
@@ -575,8 +570,8 @@ func TestVarBytesWire(t *testing.T) {
|
||||
|
||||
tests := []struct {
|
||||
in []byte // Byte Array to write
|
||||
buf []byte // Wire encoding
|
||||
pver uint32 // Protocol version for wire encoding
|
||||
buf []byte // Encoded value
|
||||
pver uint32 // Protocol version for appmessage encoding
|
||||
}{
|
||||
// Latest protocol version.
|
||||
// Empty byte array
|
||||
@@ -589,7 +584,7 @@ func TestVarBytesWire(t *testing.T) {
|
||||
|
||||
t.Logf("Running %d tests", len(tests))
|
||||
for i, test := range tests {
|
||||
// Encode to wire format.
|
||||
// Encode to appmessage format.
|
||||
var buf bytes.Buffer
|
||||
err := WriteVarBytes(&buf, test.pver, test.in)
|
||||
if err != nil {
|
||||
@@ -602,7 +597,7 @@ func TestVarBytesWire(t *testing.T) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Decode from wire format.
|
||||
// Decode from appmessage format.
|
||||
rbuf := bytes.NewReader(test.buf)
|
||||
val, err := ReadVarBytes(rbuf, test.pver, MaxMessagePayload,
|
||||
"test payload")
|
||||
@@ -618,9 +613,9 @@ func TestVarBytesWire(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestVarBytesWireErrors performs negative tests against wire encode and
|
||||
// TestVarBytesEncodingErrors performs negative tests against appmessage encode and
|
||||
// decode of variable length byte arrays to confirm error paths work correctly.
|
||||
func TestVarBytesWireErrors(t *testing.T) {
|
||||
func TestVarBytesEncodingErrors(t *testing.T) {
|
||||
pver := ProtocolVersion
|
||||
|
||||
// bytes256 is a byte array that takes a 2-byte varint to encode.
|
||||
@@ -628,8 +623,8 @@ func TestVarBytesWireErrors(t *testing.T) {
|
||||
|
||||
tests := []struct {
|
||||
in []byte // Byte Array to write
|
||||
buf []byte // Wire encoding
|
||||
pver uint32 // Protocol version for wire encoding
|
||||
buf []byte // Encoded value
|
||||
pver uint32 // Protocol version for appmessage encoding
|
||||
max int // Max size of fixed buffer to induce errors
|
||||
writeErr error // Expected write error
|
||||
readErr error // Expected read error
|
||||
@@ -645,7 +640,7 @@ func TestVarBytesWireErrors(t *testing.T) {
|
||||
|
||||
t.Logf("Running %d tests", len(tests))
|
||||
for i, test := range tests {
|
||||
// Encode to wire format.
|
||||
// Encode to appmessage format.
|
||||
w := newFixedWriter(test.max)
|
||||
err := WriteVarBytes(w, test.pver, test.in)
|
||||
if !errors.Is(err, test.writeErr) {
|
||||
@@ -654,7 +649,7 @@ func TestVarBytesWireErrors(t *testing.T) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Decode from wire format.
|
||||
// Decode from appmessage format.
|
||||
r := newFixedReader(test.max, test.buf)
|
||||
_, err = ReadVarBytes(r, test.pver, MaxMessagePayload,
|
||||
"test payload")
|
||||
@@ -674,8 +669,8 @@ func TestVarBytesOverflowErrors(t *testing.T) {
|
||||
pver := ProtocolVersion
|
||||
|
||||
tests := []struct {
|
||||
buf []byte // Wire encoding
|
||||
pver uint32 // Protocol version for wire encoding
|
||||
buf []byte // Encoded value
|
||||
pver uint32 // Protocol version for appmessage encoding
|
||||
err error // Expected error
|
||||
}{
|
||||
{[]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
|
||||
@@ -686,7 +681,7 @@ func TestVarBytesOverflowErrors(t *testing.T) {
|
||||
|
||||
t.Logf("Running %d tests", len(tests))
|
||||
for i, test := range tests {
|
||||
// Decode from wire format.
|
||||
// Decode from appmessage format.
|
||||
rbuf := bytes.NewReader(test.buf)
|
||||
_, err := ReadVarBytes(rbuf, test.pver, MaxMessagePayload,
|
||||
"test payload")
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
Package wire implements the kaspa wire protocol.
|
||||
Package appmessage implements the kaspa appmessage protocol.
|
||||
|
||||
At a high level, this package provides support for marshalling and unmarshalling
|
||||
supported kaspa messages to and from the wire. This package does not deal
|
||||
supported kaspa messages to and from the appmessage. This package does not deal
|
||||
with the specifics of message handling such as what to do when a message is
|
||||
received. This provides the caller with a high level of flexibility.
|
||||
|
||||
@@ -19,7 +19,7 @@ Message which allows messages of any type to be read, written, or passed around
|
||||
through channels, functions, etc. In addition, concrete implementations of most
|
||||
of the currently supported kaspa messages are provided. For these supported
|
||||
messages, all of the details of marshalling and unmarshalling to and from the
|
||||
wire using kaspa encoding are handled so the caller doesn't have to concern
|
||||
appmessage using kaspa encoding are handled so the caller doesn't have to concern
|
||||
themselves with the specifics.
|
||||
|
||||
Message Interaction
|
||||
@@ -55,7 +55,7 @@ Protocol Version
|
||||
|
||||
The protocol version should be negotiated with the remote peer at a higher
|
||||
level than this package via the version (MsgVersion) message exchange, however,
|
||||
this package provides the wire.ProtocolVersion constant which indicates the
|
||||
this package provides the appmessage.ProtocolVersion constant which indicates the
|
||||
latest protocol version this package supports and is typically the value to use
|
||||
for all outbound connections before a potentially lower protocol version is
|
||||
negotiated.
|
||||
@@ -66,11 +66,10 @@ The kaspa network is a magic number which is used to identify the start of a
|
||||
message and which kaspa network the message applies to. This package provides
|
||||
the following constants:
|
||||
|
||||
wire.Mainnet
|
||||
wire.Testnet (Test network)
|
||||
wire.Regtest (Regression test network)
|
||||
wire.Simnet (Simulation test network)
|
||||
wire.Devnet (Development network)
|
||||
appmessage.Mainnet
|
||||
appmessage.Testnet (Test network)
|
||||
appmessage.Simnet (Simulation test network)
|
||||
appmessage.Devnet (Development network)
|
||||
|
||||
Determining Message Type
|
||||
|
||||
@@ -82,43 +81,43 @@ switch or type assertion. An example of a type switch follows:
|
||||
// Assumes msg is already a valid concrete message such as one created
|
||||
// via NewMsgVersion or read via ReadMessage.
|
||||
switch msg := msg.(type) {
|
||||
case *wire.MsgVersion:
|
||||
case *appmessage.MsgVersion:
|
||||
// The message is a pointer to a MsgVersion struct.
|
||||
fmt.Printf("Protocol version: %d", msg.ProtocolVersion)
|
||||
case *wire.MsgBlock:
|
||||
case *appmessage.MsgBlock:
|
||||
// The message is a pointer to a MsgBlock struct.
|
||||
fmt.Printf("Number of tx in block: %d", msg.Header.TxnCount)
|
||||
}
|
||||
|
||||
Reading Messages
|
||||
|
||||
In order to unmarshall kaspa messages from the wire, use the ReadMessage
|
||||
In order to unmarshall kaspa messages from the appmessage, use the ReadMessage
|
||||
function. It accepts any io.Reader, but typically this will be a net.Conn to
|
||||
a remote node running a kaspa peer. Example syntax is:
|
||||
|
||||
// Reads and validates the next kaspa message from conn using the
|
||||
// protocol version pver and the kaspa network kaspaNet. The returns
|
||||
// are a wire.Message, a []byte which contains the unmarshalled
|
||||
// are a appmessage.Message, a []byte which contains the unmarshalled
|
||||
// raw payload, and a possible error.
|
||||
msg, rawPayload, err := wire.ReadMessage(conn, pver, kaspaNet)
|
||||
msg, rawPayload, err := appmessage.ReadMessage(conn, pver, kaspaNet)
|
||||
if err != nil {
|
||||
// Log and handle the error
|
||||
}
|
||||
|
||||
Writing Messages
|
||||
|
||||
In order to marshall kaspa messages to the wire, use the WriteMessage
|
||||
In order to marshall kaspa messages to the appmessage, use the WriteMessage
|
||||
function. It accepts any io.Writer, but typically this will be a net.Conn to
|
||||
a remote node running a kaspa peer. Example syntax to request addresses
|
||||
from a remote peer is:
|
||||
|
||||
// Create a new getaddr kaspa message.
|
||||
msg := wire.NewMsgRequestAddresses()
|
||||
msg := appmessage.NewMsgRequestAddresses()
|
||||
|
||||
// Writes a kaspa message msg to conn using the protocol version
|
||||
// pver, and the kaspa network kaspaNet. The return is a possible
|
||||
// error.
|
||||
err := wire.WriteMessage(conn, msg, pver, kaspaNet)
|
||||
err := appmessage.WriteMessage(conn, msg, pver, kaspaNet)
|
||||
if err != nil {
|
||||
// Log and handle the error
|
||||
}
|
||||
@@ -127,8 +126,8 @@ Errors
|
||||
|
||||
Errors returned by this package are either the raw errors provided by underlying
|
||||
calls to read/write from streams such as io.EOF, io.ErrUnexpectedEOF, and
|
||||
io.ErrShortWrite, or of type wire.MessageError. This allows the caller to
|
||||
io.ErrShortWrite, or of type appmessage.MessageError. This allows the caller to
|
||||
differentiate between general IO errors and malformed messages through type
|
||||
assertions.
|
||||
*/
|
||||
package wire
|
||||
package appmessage
|
||||
@@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package wire
|
||||
package appmessage
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package wire
|
||||
package appmessage
|
||||
|
||||
import "io"
|
||||
|
||||
@@ -15,7 +15,7 @@ type fakeMessage struct {
|
||||
forceLenErr bool
|
||||
}
|
||||
|
||||
// KaspaDecode doesn't do anything. It just satisfies the wire.Message
|
||||
// KaspaDecode doesn't do anything. It just satisfies the appmessage.Message
|
||||
// interface.
|
||||
func (msg *fakeMessage) KaspaDecode(r io.Reader, pver uint32) error {
|
||||
return nil
|
||||
@@ -23,7 +23,7 @@ func (msg *fakeMessage) KaspaDecode(r io.Reader, pver uint32) error {
|
||||
|
||||
// KaspaEncode writes the payload field of the fake message or forces an error
|
||||
// if the forceEncodeErr flag of the fake message is set. It also satisfies the
|
||||
// wire.Message interface.
|
||||
// appmessage.Message interface.
|
||||
func (msg *fakeMessage) KaspaEncode(w io.Writer, pver uint32) error {
|
||||
if msg.forceEncodeErr {
|
||||
err := &MessageError{
|
||||
@@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package wire
|
||||
package appmessage
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@@ -2,10 +2,11 @@
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package wire
|
||||
package appmessage
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
// MaxMessagePayload is the maximum bytes a message can be regardless of other
|
||||
@@ -46,6 +47,7 @@ const (
|
||||
CmdRequestNextIBDBlocks
|
||||
CmdDoneIBDBlocks
|
||||
CmdTransactionNotFound
|
||||
CmdReject
|
||||
)
|
||||
|
||||
// MessageCommandToString maps all MessageCommands to their string representation
|
||||
@@ -71,6 +73,7 @@ var MessageCommandToString = map[MessageCommand]string{
|
||||
CmdRequestNextIBDBlocks: "RequestNextIBDBlocks",
|
||||
CmdDoneIBDBlocks: "DoneIBDBlocks",
|
||||
CmdTransactionNotFound: "TransactionNotFound",
|
||||
CmdReject: "Reject",
|
||||
}
|
||||
|
||||
// Message is an interface that describes a kaspa message. A type that
|
||||
@@ -79,4 +82,8 @@ var MessageCommandToString = map[MessageCommand]string{
|
||||
// are used directly in the protocol encoded message.
|
||||
type Message interface {
|
||||
Command() MessageCommand
|
||||
MessageNumber() uint64
|
||||
SetMessageNumber(index uint64)
|
||||
ReceivedAt() time.Time
|
||||
SetReceivedAt(receivedAt time.Time)
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package wire
|
||||
package appmessage
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@@ -24,6 +24,7 @@ const MaxAddressesPerMsg = 1000
|
||||
// Use the AddAddress function to build up the list of known addresses when
|
||||
// sending an Addresses message to another peer.
|
||||
type MsgAddresses struct {
|
||||
baseMessage
|
||||
IncludeAllSubnetworks bool
|
||||
SubnetworkID *subnetworkid.SubnetworkID
|
||||
AddrList []*NetAddress
|
||||
@@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package wire
|
||||
package appmessage
|
||||
|
||||
import (
|
||||
"net"
|
||||
@@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package wire
|
||||
package appmessage
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@@ -42,6 +42,7 @@ type TxLoc struct {
|
||||
// block message. It is used to deliver block and transaction information in
|
||||
// response to a getdata message (MsgGetData) for a given block hash.
|
||||
type MsgBlock struct {
|
||||
baseMessage
|
||||
Header BlockHeader
|
||||
Transactions []*MsgTx
|
||||
}
|
||||
@@ -59,7 +60,7 @@ func (msg *MsgBlock) ClearTransactions() {
|
||||
// KaspaDecode decodes r using the kaspa protocol encoding into the receiver.
|
||||
// This is part of the Message interface implementation.
|
||||
// See Deserialize for decoding blocks stored to disk, such as in a database, as
|
||||
// opposed to decoding blocks from the wire.
|
||||
// opposed to decoding blocks from the appmessage.
|
||||
func (msg *MsgBlock) KaspaDecode(r io.Reader, pver uint32) error {
|
||||
err := readBlockHeader(r, pver, &msg.Header)
|
||||
if err != nil {
|
||||
@@ -96,14 +97,14 @@ func (msg *MsgBlock) KaspaDecode(r io.Reader, pver uint32) error {
|
||||
// Deserialize decodes a block from r into the receiver using a format that is
|
||||
// suitable for long-term storage such as a database while respecting the
|
||||
// Version field in the block. This function differs from KaspaDecode in that
|
||||
// KaspaDecode decodes from the kaspa wire protocol as it was sent across the
|
||||
// network. The wire encoding can technically differ depending on the protocol
|
||||
// KaspaDecode decodes from the kaspa appmessage protocol as it was sent across the
|
||||
// network. The appmessage encoding can technically differ depending on the protocol
|
||||
// version and doesn't even really need to match the format of a stored block at
|
||||
// all. As of the time this comment was written, the encoded block is the same
|
||||
// in both instances, but there is a distinct difference and separating the two
|
||||
// allows the API to be flexible enough to deal with changes.
|
||||
func (msg *MsgBlock) Deserialize(r io.Reader) error {
|
||||
// At the current time, there is no difference between the wire encoding
|
||||
// At the current time, there is no difference between the appmessage encoding
|
||||
// at protocol version 0 and the stable long-term storage format. As
|
||||
// a result, make use of KaspaDecode.
|
||||
return msg.KaspaDecode(r, 0)
|
||||
@@ -116,9 +117,9 @@ func (msg *MsgBlock) Deserialize(r io.Reader) error {
|
||||
func (msg *MsgBlock) DeserializeTxLoc(r *bytes.Buffer) ([]TxLoc, error) {
|
||||
fullLen := r.Len()
|
||||
|
||||
// At the current time, there is no difference between the wire encoding
|
||||
// At the current time, there is no difference between the appmessage encoding
|
||||
// at protocol version 0 and the stable long-term storage format. As
|
||||
// a result, make use of existing wire protocol functions.
|
||||
// a result, make use of existing appmessage protocol functions.
|
||||
err := readBlockHeader(r, 0, &msg.Header)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -159,7 +160,7 @@ func (msg *MsgBlock) DeserializeTxLoc(r *bytes.Buffer) ([]TxLoc, error) {
|
||||
// KaspaEncode encodes the receiver to w using the kaspa protocol encoding.
|
||||
// This is part of the Message interface implementation.
|
||||
// See Serialize for encoding blocks to be stored to disk, such as in a
|
||||
// database, as opposed to encoding blocks for the wire.
|
||||
// database, as opposed to encoding blocks for the appmessage.
|
||||
func (msg *MsgBlock) KaspaEncode(w io.Writer, pver uint32) error {
|
||||
err := writeBlockHeader(w, pver, &msg.Header)
|
||||
if err != nil {
|
||||
@@ -184,14 +185,14 @@ func (msg *MsgBlock) KaspaEncode(w io.Writer, pver uint32) error {
|
||||
// Serialize encodes the block to w using a format that suitable for long-term
|
||||
// storage such as a database while respecting the Version field in the block.
|
||||
// This function differs from KaspaEncode in that KaspaEncode encodes the block to
|
||||
// the kaspa wire protocol in order to be sent across the network. The wire
|
||||
// the kaspa appmessage protocol in order to be sent across the network. The appmessage
|
||||
// encoding can technically differ depending on the protocol version and doesn't
|
||||
// even really need to match the format of a stored block at all. As of the
|
||||
// time this comment was written, the encoded block is the same in both
|
||||
// instances, but there is a distinct difference and separating the two allows
|
||||
// the API to be flexible enough to deal with changes.
|
||||
func (msg *MsgBlock) Serialize(w io.Writer) error {
|
||||
// At the current time, there is no difference between the wire encoding
|
||||
// At the current time, there is no difference between the appmessage encoding
|
||||
// at protocol version 0 and the stable long-term storage format. As
|
||||
// a result, make use of KaspaEncode.
|
||||
return msg.KaspaEncode(w, 0)
|
||||
@@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package wire
|
||||
package appmessage
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@@ -144,15 +144,15 @@ func TestConvertToPartial(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestBlockWire tests the MsgBlock wire encode and decode for various numbers
|
||||
// TestBlockEncoding tests the MsgBlock appmessage encode and decode for various numbers
|
||||
// of transaction inputs and outputs and protocol versions.
|
||||
func TestBlockWire(t *testing.T) {
|
||||
func TestBlockEncoding(t *testing.T) {
|
||||
tests := []struct {
|
||||
in *MsgBlock // Message to encode
|
||||
out *MsgBlock // Expected decoded message
|
||||
buf []byte // Wire encoding
|
||||
buf []byte // Encoded value
|
||||
txLocs []TxLoc // Expected transaction locations
|
||||
pver uint32 // Protocol version for wire encoding
|
||||
pver uint32 // Protocol version for appmessage encoding
|
||||
}{
|
||||
// Latest protocol version.
|
||||
{
|
||||
@@ -166,7 +166,7 @@ func TestBlockWire(t *testing.T) {
|
||||
|
||||
t.Logf("Running %d tests", len(tests))
|
||||
for i, test := range tests {
|
||||
// Encode the message to wire format.
|
||||
// Encode the message to appmessage format.
|
||||
var buf bytes.Buffer
|
||||
err := test.in.KaspaEncode(&buf, test.pver)
|
||||
if err != nil {
|
||||
@@ -179,7 +179,7 @@ func TestBlockWire(t *testing.T) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Decode the message from wire format.
|
||||
// Decode the message from appmessage format.
|
||||
var msg MsgBlock
|
||||
rbuf := bytes.NewReader(test.buf)
|
||||
err = msg.KaspaDecode(rbuf, test.pver)
|
||||
@@ -195,15 +195,15 @@ func TestBlockWire(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestBlockWireErrors performs negative tests against wire encode and decode
|
||||
// TestBlockEncodingErrors performs negative tests against appmessage encode and decode
|
||||
// of MsgBlock to confirm error paths work correctly.
|
||||
func TestBlockWireErrors(t *testing.T) {
|
||||
func TestBlockEncodingErrors(t *testing.T) {
|
||||
pver := ProtocolVersion
|
||||
|
||||
tests := []struct {
|
||||
in *MsgBlock // Value to encode
|
||||
buf []byte // Wire encoding
|
||||
pver uint32 // Protocol version for wire encoding
|
||||
buf []byte // Encoded value
|
||||
pver uint32 // Protocol version for appmessage encoding
|
||||
max int // Max size of fixed buffer to induce errors
|
||||
writeErr error // Expected write error
|
||||
readErr error // Expected read error
|
||||
@@ -236,7 +236,7 @@ func TestBlockWireErrors(t *testing.T) {
|
||||
|
||||
t.Logf("Running %d tests", len(tests))
|
||||
for i, test := range tests {
|
||||
// Encode to wire format.
|
||||
// Encode to appmessage format.
|
||||
w := newFixedWriter(test.max)
|
||||
err := test.in.KaspaEncode(w, test.pver)
|
||||
if !errors.Is(err, test.writeErr) {
|
||||
@@ -245,7 +245,7 @@ func TestBlockWireErrors(t *testing.T) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Decode from wire format.
|
||||
// Decode from appmessage format.
|
||||
var msg MsgBlock
|
||||
r := newFixedReader(test.max, test.buf)
|
||||
err = msg.KaspaDecode(r, test.pver)
|
||||
@@ -324,7 +324,7 @@ func TestBlockSerialize(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestBlockSerializeErrors performs negative tests against wire encode and
|
||||
// TestBlockSerializeErrors performs negative tests against appmessage encode and
|
||||
// decode of MsgBlock to confirm error paths work correctly.
|
||||
func TestBlockSerializeErrors(t *testing.T) {
|
||||
tests := []struct {
|
||||
@@ -400,8 +400,8 @@ func TestBlockOverflowErrors(t *testing.T) {
|
||||
pver := ProtocolVersion
|
||||
|
||||
tests := []struct {
|
||||
buf []byte // Wire encoding
|
||||
pver uint32 // Protocol version for wire encoding
|
||||
buf []byte // Encoded value
|
||||
pver uint32 // Protocol version for appmessage encoding
|
||||
err error // Expected error
|
||||
}{
|
||||
// Block that claims to have ~uint64(0) transactions.
|
||||
@@ -431,7 +431,7 @@ func TestBlockOverflowErrors(t *testing.T) {
|
||||
0x65, 0x9C, 0x79, 0x3C, 0xE3, 0x70, 0xD9, 0x5F,
|
||||
0x61, 0xbc, 0x66, 0x49, 0x00, 0x00, 0x00, 0x00, // Timestamp
|
||||
0xff, 0xff, 0x00, 0x1d, // Bits
|
||||
0x01, 0xe3, 0x62, 0x99, 0x00, 0x00, 0x00, 0x00, // Fake Nonce. TODO: (Ori) Replace to a real nonce
|
||||
0x01, 0xe3, 0x62, 0x99, 0x00, 0x00, 0x00, 0x00, // Fake Nonce
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, // TxnCount
|
||||
}, pver, &MessageError{},
|
||||
@@ -440,7 +440,7 @@ func TestBlockOverflowErrors(t *testing.T) {
|
||||
|
||||
t.Logf("Running %d tests", len(tests))
|
||||
for i, test := range tests {
|
||||
// Decode from wire format.
|
||||
// Decode from appmessage format.
|
||||
var msg MsgBlock
|
||||
r := bytes.NewReader(test.buf)
|
||||
err := msg.KaspaDecode(r, test.pver)
|
||||
@@ -450,7 +450,7 @@ func TestBlockOverflowErrors(t *testing.T) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Deserialize from wire format.
|
||||
// Deserialize from appmessage format.
|
||||
r = bytes.NewReader(test.buf)
|
||||
err = msg.Deserialize(r)
|
||||
if reflect.TypeOf(err) != reflect.TypeOf(test.err) {
|
||||
@@ -459,7 +459,7 @@ func TestBlockOverflowErrors(t *testing.T) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Deserialize with transaction location info from wire format.
|
||||
// Deserialize with transaction location info from appmessage format.
|
||||
br := bytes.NewBuffer(test.buf)
|
||||
_, err = msg.DeserializeTxLoc(br)
|
||||
if reflect.TypeOf(err) != reflect.TypeOf(test.err) {
|
||||
@@ -572,7 +572,7 @@ var blockOneBytes = []byte{
|
||||
0x65, 0x9C, 0x79, 0x3C, 0xE3, 0x70, 0xD9, 0x5F,
|
||||
0x99, 0x0f, 0xed, 0x15, 0x73, 0x01, 0x00, 0x00, // Timestamp
|
||||
0xff, 0xff, 0x00, 0x1d, // Bits
|
||||
0x01, 0xe3, 0x62, 0x99, 0x00, 0x00, 0x00, 0x00, // Fake Nonce. TODO: (Ori) Replace to a real nonce
|
||||
0x01, 0xe3, 0x62, 0x99, 0x00, 0x00, 0x00, 0x00, // Fake Nonce
|
||||
0x01, // TxnCount
|
||||
0x01, 0x00, 0x00, 0x00, // Version
|
||||
0x01, // Varint for number of transaction inputs
|
||||
@@ -1,4 +1,4 @@
|
||||
package wire
|
||||
package appmessage
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/util/daghash"
|
||||
@@ -12,6 +12,7 @@ const MaxBlockLocatorsPerMsg = 500
|
||||
// locator message. It is used to find the blockLocator of a peer that is
|
||||
// syncing with you.
|
||||
type MsgBlockLocator struct {
|
||||
baseMessage
|
||||
BlockLocatorHashes []*daghash.Hash
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package wire
|
||||
package appmessage
|
||||
|
||||
import (
|
||||
"testing"
|
||||
@@ -1,11 +1,13 @@
|
||||
package wire
|
||||
package appmessage
|
||||
|
||||
// MsgDoneIBDBlocks implements the Message interface and represents a kaspa
|
||||
// DoneIBDBlocks message. It is used to notify the IBD syncing peer that the
|
||||
// syncer sent all the requested blocks.
|
||||
//
|
||||
// This message has no payload.
|
||||
type MsgDoneIBDBlocks struct{}
|
||||
type MsgDoneIBDBlocks struct {
|
||||
baseMessage
|
||||
}
|
||||
|
||||
// Command returns the protocol command string for the message. This is part
|
||||
// of the Message interface implementation.
|
||||
@@ -2,12 +2,13 @@
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package wire
|
||||
package appmessage
|
||||
|
||||
// MsgIBDBlock implements the Message interface and represents a kaspa
|
||||
// ibdblock message. It is used to deliver block and transaction information in
|
||||
// response to a RequestIBDBlocks message (MsgRequestIBDBlocks).
|
||||
type MsgIBDBlock struct {
|
||||
baseMessage
|
||||
*MsgBlock
|
||||
}
|
||||
|
||||
@@ -26,5 +27,5 @@ func (msg *MsgIBDBlock) MaxPayloadLength(pver uint32) uint32 {
|
||||
// NewMsgIBDBlock returns a new kaspa ibdblock message that conforms to the
|
||||
// Message interface. See MsgIBDBlock for details.
|
||||
func NewMsgIBDBlock(msgBlock *MsgBlock) *MsgIBDBlock {
|
||||
return &MsgIBDBlock{msgBlock}
|
||||
return &MsgIBDBlock{MsgBlock: msgBlock}
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package wire
|
||||
package appmessage
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@@ -65,20 +65,20 @@ func TestIBDBlock(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestIBDBlockWire tests the MsgIBDBlock wire encode and decode for various numbers
|
||||
// TestIBDBlockEncoding tests the MsgIBDBlock appmessage encode and decode for various numbers
|
||||
// of transaction inputs and outputs and protocol versions.
|
||||
func TestIBDBlockWire(t *testing.T) {
|
||||
func TestIBDBlockEncoding(t *testing.T) {
|
||||
tests := []struct {
|
||||
in *MsgIBDBlock // Message to encode
|
||||
out *MsgIBDBlock // Expected decoded message
|
||||
buf []byte // Wire encoding
|
||||
buf []byte // Encoded value
|
||||
txLocs []TxLoc // Expected transaction locations
|
||||
pver uint32 // Protocol version for wire encoding
|
||||
pver uint32 // Protocol version for appmessage encoding
|
||||
}{
|
||||
// Latest protocol version.
|
||||
{
|
||||
&MsgIBDBlock{&blockOne},
|
||||
&MsgIBDBlock{&blockOne},
|
||||
&MsgIBDBlock{MsgBlock: &blockOne},
|
||||
&MsgIBDBlock{MsgBlock: &blockOne},
|
||||
blockOneBytes,
|
||||
blockOneTxLocs,
|
||||
ProtocolVersion,
|
||||
@@ -87,7 +87,7 @@ func TestIBDBlockWire(t *testing.T) {
|
||||
|
||||
t.Logf("Running %d tests", len(tests))
|
||||
for i, test := range tests {
|
||||
// Encode the message to wire format.
|
||||
// Encode the message to appmessage format.
|
||||
var buf bytes.Buffer
|
||||
err := test.in.KaspaEncode(&buf, test.pver)
|
||||
if err != nil {
|
||||
@@ -100,7 +100,7 @@ func TestIBDBlockWire(t *testing.T) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Decode the message from wire format.
|
||||
// Decode the message from appmessage format.
|
||||
var msg MsgIBDBlock
|
||||
msg.MsgBlock = new(MsgBlock)
|
||||
rbuf := bytes.NewReader(test.buf)
|
||||
@@ -1,4 +1,4 @@
|
||||
package wire
|
||||
package appmessage
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/util/daghash"
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
// block inventory message. It is used to notify the network about new block
|
||||
// by sending their hash, and let the receiving node decide if it needs it.
|
||||
type MsgInvRelayBlock struct {
|
||||
baseMessage
|
||||
Hash *daghash.Hash
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package wire
|
||||
package appmessage
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/util/daghash"
|
||||
@@ -12,6 +12,7 @@ const MaxInvPerTxInvMsg = MaxInvPerMsg
|
||||
// TxInv message. It is used to notify the network about new transactions
|
||||
// by sending their ID, and let the receiving node decide if it needs it.
|
||||
type MsgInvTransaction struct {
|
||||
baseMessage
|
||||
TxIDs []*daghash.TxID
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package wire
|
||||
package appmessage
|
||||
|
||||
// MsgPing implements the Message interface and represents a kaspa ping
|
||||
// message.
|
||||
@@ -16,6 +16,7 @@ package wire
|
||||
// The payload for this message just consists of a nonce used for identifying
|
||||
// it later.
|
||||
type MsgPing struct {
|
||||
baseMessage
|
||||
// Unique value associated with message that is used to identify
|
||||
// specific ping message.
|
||||
Nonce uint64
|
||||
@@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package wire
|
||||
package appmessage
|
||||
|
||||
import (
|
||||
"testing"
|
||||
@@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package wire
|
||||
package appmessage
|
||||
|
||||
// MsgPong implements the Message interface and represents a kaspa pong
|
||||
// message which is used primarily to confirm that a connection is still valid
|
||||
@@ -10,6 +10,7 @@ package wire
|
||||
//
|
||||
// This message was not added until protocol versions AFTER BIP0031Version.
|
||||
type MsgPong struct {
|
||||
baseMessage
|
||||
// Unique value associated with message that is used to identify
|
||||
// specific ping message.
|
||||
Nonce uint64
|
||||
@@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package wire
|
||||
package appmessage
|
||||
|
||||
import (
|
||||
"testing"
|
||||
22
app/appmessage/msgreject.go
Normal file
22
app/appmessage/msgreject.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package appmessage
|
||||
|
||||
// MsgReject implements the Message interface and represents a kaspa
|
||||
// Reject message. It is used to notify peers why they are banned.
|
||||
type MsgReject struct {
|
||||
baseMessage
|
||||
Reason string
|
||||
}
|
||||
|
||||
// Command returns the protocol command string for the message. This is part
|
||||
// of the Message interface implementation.
|
||||
func (msg *MsgReject) Command() MessageCommand {
|
||||
return CmdReject
|
||||
}
|
||||
|
||||
// NewMsgReject returns a new kaspa Reject message that conforms to the
|
||||
// Message interface.
|
||||
func NewMsgReject(reason string) *MsgReject {
|
||||
return &MsgReject{
|
||||
Reason: reason,
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package wire
|
||||
package appmessage
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/util/subnetworkid"
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
//
|
||||
// This message has no payload.
|
||||
type MsgRequestAddresses struct {
|
||||
baseMessage
|
||||
IncludeAllSubnetworks bool
|
||||
SubnetworkID *subnetworkid.SubnetworkID
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package wire
|
||||
package appmessage
|
||||
|
||||
import (
|
||||
"testing"
|
||||
@@ -1,4 +1,4 @@
|
||||
package wire
|
||||
package appmessage
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/util/daghash"
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
// and low hash.
|
||||
// The locator is returned via a locator message (MsgBlockLocator).
|
||||
type MsgRequestBlockLocator struct {
|
||||
baseMessage
|
||||
HighHash *daghash.Hash
|
||||
LowHash *daghash.Hash
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package wire
|
||||
package appmessage
|
||||
|
||||
import (
|
||||
"testing"
|
||||
@@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package wire
|
||||
package appmessage
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/util/daghash"
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
// RequestIBDBlocks message. It is used to request a list of blocks starting after the
|
||||
// low hash and until the high hash.
|
||||
type MsgRequestIBDBlocks struct {
|
||||
baseMessage
|
||||
LowHash *daghash.Hash
|
||||
HighHash *daghash.Hash
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package wire
|
||||
package appmessage
|
||||
|
||||
import (
|
||||
"testing"
|
||||
@@ -1,11 +1,13 @@
|
||||
package wire
|
||||
package appmessage
|
||||
|
||||
// MsgRequestNextIBDBlocks implements the Message interface and represents a kaspa
|
||||
// RequestNextIBDBlocks message. It is used to notify the IBD syncer peer to send
|
||||
// more blocks.
|
||||
//
|
||||
// This message has no payload.
|
||||
type MsgRequestNextIBDBlocks struct{}
|
||||
type MsgRequestNextIBDBlocks struct {
|
||||
baseMessage
|
||||
}
|
||||
|
||||
// Command returns the protocol command string for the message. This is part
|
||||
// of the Message interface implementation.
|
||||
@@ -1,4 +1,4 @@
|
||||
package wire
|
||||
package appmessage
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/util/daghash"
|
||||
@@ -12,6 +12,7 @@ const MsgRequestRelayBlocksHashes = MaxInvPerMsg
|
||||
// RequestRelayBlocks message. It is used to request blocks as part of the block
|
||||
// relay protocol.
|
||||
type MsgRequestRelayBlocks struct {
|
||||
baseMessage
|
||||
Hashes []*daghash.Hash
|
||||
}
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
package wire
|
||||
package appmessage
|
||||
|
||||
// MsgRequestSelectedTip implements the Message interface and represents a kaspa
|
||||
// RequestSelectedTip message. It is used to request the selected tip of another peer.
|
||||
//
|
||||
// This message has no payload.
|
||||
type MsgRequestSelectedTip struct{}
|
||||
type MsgRequestSelectedTip struct {
|
||||
baseMessage
|
||||
}
|
||||
|
||||
// Command returns the protocol command string for the message. This is part
|
||||
// of the Message interface implementation.
|
||||
@@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package wire
|
||||
package appmessage
|
||||
|
||||
import (
|
||||
"testing"
|
||||
@@ -1,4 +1,4 @@
|
||||
package wire
|
||||
package appmessage
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/util/daghash"
|
||||
@@ -12,6 +12,7 @@ const MaxInvPerRequestTransactionsMsg = MaxInvPerMsg
|
||||
// RequestTransactions message. It is used to request transactions as part of the
|
||||
// transactions relay protocol.
|
||||
type MsgRequestTransactions struct {
|
||||
baseMessage
|
||||
IDs []*daghash.TxID
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package wire
|
||||
package appmessage
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/util/daghash"
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
// selectedtip message. It is used to answer getseltip messages and tell
|
||||
// the asking peer what is the selected tip of this peer.
|
||||
type MsgSelectedTip struct {
|
||||
baseMessage
|
||||
// The selected tip hash of the generator of the message.
|
||||
SelectedTipHash *daghash.Hash
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package wire
|
||||
package appmessage
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/util/daghash"
|
||||
@@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package wire
|
||||
package appmessage
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/util/daghash"
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
// MsgTransactionNotFound defines a kaspa TransactionNotFound message which is sent in response to
|
||||
// a RequestTransactions message if any of the requested data in not available on the peer.
|
||||
type MsgTransactionNotFound struct {
|
||||
baseMessage
|
||||
ID *daghash.TxID
|
||||
}
|
||||
|
||||
@@ -2,10 +2,9 @@
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package wire
|
||||
package appmessage
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
@@ -84,7 +83,7 @@ const (
|
||||
minTxPayload = 10
|
||||
|
||||
// freeListMaxScriptSize is the size of each buffer in the free list
|
||||
// that is used for deserializing scripts from the wire before they are
|
||||
// that is used for deserializing scripts from the appmessage before they are
|
||||
// concatenated into a single contiguous buffers. This value was chosen
|
||||
// because it is slightly more than twice the size of the vast majority
|
||||
// of all "standard" scripts. Larger scripts are still deserialized
|
||||
@@ -268,6 +267,7 @@ func NewTxOut(value uint64, scriptPubKey []byte) *TxOut {
|
||||
// Use the AddTxIn and AddTxOut functions to build up the list of transaction
|
||||
// inputs and outputs.
|
||||
type MsgTx struct {
|
||||
baseMessage
|
||||
Version int32
|
||||
TxIn []*TxIn
|
||||
TxOut []*TxOut
|
||||
@@ -301,29 +301,34 @@ func (msg *MsgTx) IsCoinBase() bool {
|
||||
// TxHash generates the Hash for the transaction.
|
||||
func (msg *MsgTx) TxHash() *daghash.Hash {
|
||||
// Encode the transaction and calculate double sha256 on the result.
|
||||
// Ignore the error returns since the only way the encode could fail
|
||||
// is being out of memory or due to nil pointers, both of which would
|
||||
// cause a run-time panic.
|
||||
buf := bytes.NewBuffer(make([]byte, 0, msg.serializeSize(txEncodingExcludePayload)))
|
||||
_ = msg.serialize(buf, txEncodingExcludePayload)
|
||||
writer := daghash.NewDoubleHashWriter()
|
||||
err := msg.serialize(writer, txEncodingExcludePayload)
|
||||
if err != nil {
|
||||
// this writer never return errors (no allocations or possible failures) so errors can only come from validity checks,
|
||||
// and we assume we never construct malformed transactions.
|
||||
panic(fmt.Sprintf("TxHash() failed. this should never fail for structurally-valid transactions. err: %+v", err))
|
||||
}
|
||||
|
||||
hash := daghash.Hash(daghash.DoubleHashH(buf.Bytes()))
|
||||
hash := writer.Finalize()
|
||||
return &hash
|
||||
}
|
||||
|
||||
// TxID generates the Hash for the transaction without the signature script, gas and payload fields.
|
||||
func (msg *MsgTx) TxID() *daghash.TxID {
|
||||
// Encode the transaction, replace signature script with zeroes, cut off
|
||||
// payload and calculate double sha256 on the result. Ignore the error
|
||||
// returns since the only way the encode could fail is being out of memory or
|
||||
// due to nil pointers, both of which would cause a run-time panic.
|
||||
// payload and calculate double sha256 on the result.
|
||||
var encodingFlags txEncoding
|
||||
if !msg.IsCoinBase() {
|
||||
encodingFlags = txEncodingExcludeSignatureScript | txEncodingExcludePayload
|
||||
}
|
||||
buf := bytes.NewBuffer(make([]byte, 0, msg.serializeSize(encodingFlags)))
|
||||
_ = msg.serialize(buf, encodingFlags)
|
||||
txID := daghash.TxID(daghash.DoubleHashH(buf.Bytes()))
|
||||
writer := daghash.NewDoubleHashWriter()
|
||||
err := msg.serialize(writer, encodingFlags)
|
||||
if err != nil {
|
||||
// this writer never return errors (no allocations or possible failures) so errors can only come from validity checks,
|
||||
// and we assume we never construct malformed transactions.
|
||||
panic(fmt.Sprintf("TxID() failed. this should never fail for structurally-valid transactions. err: %+v", err))
|
||||
}
|
||||
txID := daghash.TxID(writer.Finalize())
|
||||
return &txID
|
||||
}
|
||||
|
||||
@@ -401,7 +406,7 @@ func (msg *MsgTx) Copy() *MsgTx {
|
||||
// KaspaDecode decodes r using the kaspa protocol encoding into the receiver.
|
||||
// This is part of the Message interface implementation.
|
||||
// See Deserialize for decoding transactions stored to disk, such as in a
|
||||
// database, as opposed to decoding transactions from the wire.
|
||||
// database, as opposed to decoding transactions from the appmessage.
|
||||
func (msg *MsgTx) KaspaDecode(r io.Reader, pver uint32) error {
|
||||
version, err := binaryserializer.Uint32(r, littleEndian)
|
||||
if err != nil {
|
||||
@@ -591,15 +596,15 @@ func (msg *MsgTx) KaspaDecode(r io.Reader, pver uint32) error {
|
||||
// Deserialize decodes a transaction from r into the receiver using a format
|
||||
// that is suitable for long-term storage such as a database while respecting
|
||||
// the Version field in the transaction. This function differs from KaspaDecode
|
||||
// in that KaspaDecode decodes from the kaspa wire protocol as it was sent
|
||||
// across the network. The wire encoding can technically differ depending on
|
||||
// in that KaspaDecode decodes from the kaspa appmessage protocol as it was sent
|
||||
// across the network. The appmessage encoding can technically differ depending on
|
||||
// the protocol version and doesn't even really need to match the format of a
|
||||
// stored transaction at all. As of the time this comment was written, the
|
||||
// encoded transaction is the same in both instances, but there is a distinct
|
||||
// difference and separating the two allows the API to be flexible enough to
|
||||
// deal with changes.
|
||||
func (msg *MsgTx) Deserialize(r io.Reader) error {
|
||||
// At the current time, there is no difference between the wire encoding
|
||||
// At the current time, there is no difference between the appmessage encoding
|
||||
// at protocol version 0 and the stable long-term storage format. As
|
||||
// a result, make use of KaspaDecode.
|
||||
return msg.KaspaDecode(r, 0)
|
||||
@@ -608,7 +613,7 @@ func (msg *MsgTx) Deserialize(r io.Reader) error {
|
||||
// KaspaEncode encodes the receiver to w using the kaspa protocol encoding.
|
||||
// This is part of the Message interface implementation.
|
||||
// See Serialize for encoding transactions to be stored to disk, such as in a
|
||||
// database, as opposed to encoding transactions for the wire.
|
||||
// database, as opposed to encoding transactions for the appmessage.
|
||||
func (msg *MsgTx) KaspaEncode(w io.Writer, pver uint32) error {
|
||||
return msg.encode(w, pver, txEncodingFull)
|
||||
}
|
||||
@@ -697,22 +702,22 @@ func (msg *MsgTx) encode(w io.Writer, pver uint32, encodingFlags txEncoding) err
|
||||
// Serialize encodes the transaction to w using a format that suitable for
|
||||
// long-term storage such as a database while respecting the Version field in
|
||||
// the transaction. This function differs from KaspaEncode in that KaspaEncode
|
||||
// encodes the transaction to the kaspa wire protocol in order to be sent
|
||||
// across the network. The wire encoding can technically differ depending on
|
||||
// encodes the transaction to the kaspa appmessage protocol in order to be sent
|
||||
// across the network. The appmessage encoding can technically differ depending on
|
||||
// the protocol version and doesn't even really need to match the format of a
|
||||
// stored transaction at all. As of the time this comment was written, the
|
||||
// encoded transaction is the same in both instances, but there is a distinct
|
||||
// difference and separating the two allows the API to be flexible enough to
|
||||
// deal with changes.
|
||||
func (msg *MsgTx) Serialize(w io.Writer) error {
|
||||
// At the current time, there is no difference between the wire encoding
|
||||
// At the current time, there is no difference between the appmessage encoding
|
||||
// at protocol version 0 and the stable long-term storage format. As
|
||||
// a result, make use of KaspaEncode.
|
||||
return msg.KaspaEncode(w, 0)
|
||||
}
|
||||
|
||||
func (msg *MsgTx) serialize(w io.Writer, encodingFlags txEncoding) error {
|
||||
// At the current time, there is no difference between the wire encoding
|
||||
// At the current time, there is no difference between the appmessage encoding
|
||||
// at protocol version 0 and the stable long-term storage format. As
|
||||
// a result, make use of `encode`.
|
||||
return msg.encode(w, 0, encodingFlags)
|
||||
@@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package wire
|
||||
package appmessage
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@@ -253,9 +253,9 @@ func TestTxHashAndID(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestTxWire tests the MsgTx wire encode and decode for various numbers
|
||||
// TestTxEncoding tests the MsgTx appmessage encode and decode for various numbers
|
||||
// of transaction inputs and outputs and protocol versions.
|
||||
func TestTxWire(t *testing.T) {
|
||||
func TestTxEncoding(t *testing.T) {
|
||||
// Empty tx message.
|
||||
noTx := NewNativeMsgTx(1, nil, nil)
|
||||
noTxEncoded := []byte{
|
||||
@@ -271,8 +271,8 @@ func TestTxWire(t *testing.T) {
|
||||
tests := []struct {
|
||||
in *MsgTx // Message to encode
|
||||
out *MsgTx // Expected decoded message
|
||||
buf []byte // Wire encoding
|
||||
pver uint32 // Protocol version for wire encoding
|
||||
buf []byte // Encoded value
|
||||
pver uint32 // Protocol version for appmessage encoding
|
||||
}{
|
||||
// Latest protocol version with no transactions.
|
||||
{
|
||||
@@ -293,7 +293,7 @@ func TestTxWire(t *testing.T) {
|
||||
|
||||
t.Logf("Running %d tests", len(tests))
|
||||
for i, test := range tests {
|
||||
// Encode the message to wire format.
|
||||
// Encode the message to appmessage format.
|
||||
var buf bytes.Buffer
|
||||
err := test.in.KaspaEncode(&buf, test.pver)
|
||||
if err != nil {
|
||||
@@ -306,7 +306,7 @@ func TestTxWire(t *testing.T) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Decode the message from wire format.
|
||||
// Decode the message from appmessage format.
|
||||
var msg MsgTx
|
||||
rbuf := bytes.NewReader(test.buf)
|
||||
err = msg.KaspaDecode(rbuf, test.pver)
|
||||
@@ -322,15 +322,15 @@ func TestTxWire(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestTxWireErrors performs negative tests against wire encode and decode
|
||||
// TestTxEncodingErrors performs negative tests against appmessage encode and decode
|
||||
// of MsgTx to confirm error paths work correctly.
|
||||
func TestTxWireErrors(t *testing.T) {
|
||||
func TestTxEncodingErrors(t *testing.T) {
|
||||
pver := ProtocolVersion
|
||||
|
||||
tests := []struct {
|
||||
in *MsgTx // Value to encode
|
||||
buf []byte // Wire encoding
|
||||
pver uint32 // Protocol version for wire encoding
|
||||
buf []byte // Encoded value
|
||||
pver uint32 // Protocol version for appmessage encoding
|
||||
max int // Max size of fixed buffer to induce errors
|
||||
writeErr error // Expected write error
|
||||
readErr error // Expected read error
|
||||
@@ -363,7 +363,7 @@ func TestTxWireErrors(t *testing.T) {
|
||||
|
||||
t.Logf("Running %d tests", len(tests))
|
||||
for i, test := range tests {
|
||||
// Encode to wire format.
|
||||
// Encode to appmessage format.
|
||||
w := newFixedWriter(test.max)
|
||||
err := test.in.KaspaEncode(w, test.pver)
|
||||
if !errors.Is(err, test.writeErr) {
|
||||
@@ -372,7 +372,7 @@ func TestTxWireErrors(t *testing.T) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Decode from wire format.
|
||||
// Decode from appmessage format.
|
||||
var msg MsgTx
|
||||
r := newFixedReader(test.max, test.buf)
|
||||
err = msg.KaspaDecode(r, test.pver)
|
||||
@@ -528,7 +528,7 @@ func TestTxSerialize(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestTxSerializeErrors performs negative tests against wire encode and decode
|
||||
// TestTxSerializeErrors performs negative tests against appmessage encode and decode
|
||||
// of MsgTx to confirm error paths work correctly.
|
||||
func TestTxSerializeErrors(t *testing.T) {
|
||||
tests := []struct {
|
||||
@@ -628,8 +628,8 @@ func TestTxOverflowErrors(t *testing.T) {
|
||||
txVer := uint32(1)
|
||||
|
||||
tests := []struct {
|
||||
buf []byte // Wire encoding
|
||||
pver uint32 // Protocol version for wire encoding
|
||||
buf []byte // Encoded value
|
||||
pver uint32 // Protocol version for appmessage encoding
|
||||
version uint32 // Transaction version
|
||||
err error // Expected error
|
||||
}{
|
||||
@@ -691,7 +691,7 @@ func TestTxOverflowErrors(t *testing.T) {
|
||||
|
||||
t.Logf("Running %d tests", len(tests))
|
||||
for i, test := range tests {
|
||||
// Decode from wire format.
|
||||
// Decode from appmessage format.
|
||||
var msg MsgTx
|
||||
r := bytes.NewReader(test.buf)
|
||||
err := msg.KaspaDecode(r, test.pver)
|
||||
@@ -701,7 +701,7 @@ func TestTxOverflowErrors(t *testing.T) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Decode from wire format.
|
||||
// Decode from appmessage format.
|
||||
r = bytes.NewReader(test.buf)
|
||||
err = msg.Deserialize(r)
|
||||
if reflect.TypeOf(err) != reflect.TypeOf(test.err) {
|
||||
@@ -891,7 +891,7 @@ var multiTxOuts = []*TxOut{
|
||||
}
|
||||
var multiTx = NewNativeMsgTx(1, multiTxIns, multiTxOuts)
|
||||
|
||||
// multiTxEncoded is the wire encoded bytes for multiTx using protocol version
|
||||
// multiTxEncoded is the appmessage encoded bytes for multiTx using protocol version
|
||||
// 60002 and is used in the various tests.
|
||||
var multiTxEncoded = []byte{
|
||||
0x01, 0x00, 0x00, 0x00, // Version
|
||||
@@ -2,14 +2,16 @@
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package wire
|
||||
package appmessage
|
||||
|
||||
// MsgVerAck defines a kaspa verack message which is used for a peer to
|
||||
// acknowledge a version message (MsgVersion) after it has used the information
|
||||
// to negotiate parameters. It implements the Message interface.
|
||||
//
|
||||
// This message has no payload.
|
||||
type MsgVerAck struct{}
|
||||
type MsgVerAck struct {
|
||||
baseMessage
|
||||
}
|
||||
|
||||
// Command returns the protocol command string for the message. This is part
|
||||
// of the Message interface implementation.
|
||||
@@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package wire
|
||||
package appmessage
|
||||
|
||||
import (
|
||||
"testing"
|
||||
@@ -2,15 +2,15 @@
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package wire
|
||||
package appmessage
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/kaspanet/kaspad/version"
|
||||
"strings"
|
||||
|
||||
"github.com/kaspanet/kaspad/netadapter/id"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/id"
|
||||
"github.com/kaspanet/kaspad/util/mstime"
|
||||
"github.com/kaspanet/kaspad/version"
|
||||
|
||||
"github.com/kaspanet/kaspad/util/daghash"
|
||||
"github.com/kaspanet/kaspad/util/subnetworkid"
|
||||
@@ -20,7 +20,7 @@ import (
|
||||
// version message (MsgVersion).
|
||||
const MaxUserAgentLen = 256
|
||||
|
||||
// DefaultUserAgent for wire in the stack
|
||||
// DefaultUserAgent for appmessage in the stack
|
||||
var DefaultUserAgent = fmt.Sprintf("/kaspad:%s/", version.Version())
|
||||
|
||||
// MsgVersion implements the Message interface and represents a kaspa version
|
||||
@@ -31,13 +31,17 @@ var DefaultUserAgent = fmt.Sprintf("/kaspad:%s/", version.Version())
|
||||
// message (MsgVerAck). This exchange must take place before any further
|
||||
// communication is allowed to proceed.
|
||||
type MsgVersion struct {
|
||||
baseMessage
|
||||
// Version of the protocol the node is using.
|
||||
ProtocolVersion uint32
|
||||
|
||||
// The peer's network (mainnet, testnet, etc.)
|
||||
Network string
|
||||
|
||||
// Bitfield which identifies the enabled services.
|
||||
Services ServiceFlag
|
||||
|
||||
// Time the message was generated. This is encoded as an int64 on the wire.
|
||||
// Time the message was generated. This is encoded as an int64 on the appmessage.
|
||||
Timestamp mstime.Time
|
||||
|
||||
// Address of the local peer.
|
||||
@@ -47,7 +51,7 @@ type MsgVersion struct {
|
||||
ID *id.ID
|
||||
|
||||
// The user agent that generated messsage. This is a encoded as a varString
|
||||
// on the wire. This has a max length of MaxUserAgentLen.
|
||||
// on the appmessage. This has a max length of MaxUserAgentLen.
|
||||
UserAgent string
|
||||
|
||||
// The selected tip hash of the generator of the version message.
|
||||
@@ -81,13 +85,14 @@ func (msg *MsgVersion) Command() MessageCommand {
|
||||
// NewMsgVersion returns a new kaspa version message that conforms to the
|
||||
// Message interface using the passed parameters and defaults for the remaining
|
||||
// fields.
|
||||
func NewMsgVersion(addr *NetAddress, id *id.ID,
|
||||
func NewMsgVersion(addr *NetAddress, id *id.ID, network string,
|
||||
selectedTipHash *daghash.Hash, subnetworkID *subnetworkid.SubnetworkID) *MsgVersion {
|
||||
|
||||
// Limit the timestamp to one millisecond precision since the protocol
|
||||
// doesn't support better.
|
||||
return &MsgVersion{
|
||||
ProtocolVersion: ProtocolVersion,
|
||||
Network: network,
|
||||
Services: 0,
|
||||
Timestamp: mstime.Now(),
|
||||
Address: addr,
|
||||
@@ -2,11 +2,11 @@
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package wire
|
||||
package appmessage
|
||||
|
||||
import (
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
id "github.com/kaspanet/kaspad/netadapter/id"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/id"
|
||||
"github.com/kaspanet/kaspad/util/daghash"
|
||||
"net"
|
||||
"reflect"
|
||||
@@ -27,7 +27,7 @@ func TestVersion(t *testing.T) {
|
||||
}
|
||||
|
||||
// Ensure we get the correct data back out.
|
||||
msg := NewMsgVersion(me, generatedID, selectedTipHash, nil)
|
||||
msg := NewMsgVersion(me, generatedID, "mainnet", selectedTipHash, nil)
|
||||
if msg.ProtocolVersion != pver {
|
||||
t.Errorf("NewMsgVersion: wrong protocol version - got %v, want %v",
|
||||
msg.ProtocolVersion, pver)
|
||||
@@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package wire
|
||||
package appmessage
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/util/mstime"
|
||||
@@ -21,7 +21,7 @@ type NetAddress struct {
|
||||
// IP address of the peer.
|
||||
IP net.IP
|
||||
|
||||
// Port the peer is using. This is encoded in big endian on the wire
|
||||
// Port the peer is using. This is encoded in big endian on the appmessage
|
||||
// which differs from most everything else.
|
||||
Port uint16
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package wire
|
||||
package appmessage
|
||||
|
||||
import (
|
||||
"net"
|
||||
@@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package wire
|
||||
package appmessage
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@@ -10,10 +10,13 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// XXX pedro: we will probably need to bump this.
|
||||
const (
|
||||
// ProtocolVersion is the latest protocol version this package supports.
|
||||
ProtocolVersion uint32 = 1
|
||||
|
||||
// DefaultServices describes the default services that are supported by
|
||||
// the server.
|
||||
DefaultServices = SFNodeNetwork | SFNodeBloom | SFNodeCF
|
||||
)
|
||||
|
||||
// ServiceFlag identifies services supported by a kaspa peer.
|
||||
@@ -103,9 +106,6 @@ const (
|
||||
// Testnet represents the test network.
|
||||
Testnet KaspaNet = 0xddb8af8f
|
||||
|
||||
// Regtest represents the regression test network.
|
||||
Regtest KaspaNet = 0xf396cdd6
|
||||
|
||||
// Simnet represents the simulation test network.
|
||||
Simnet KaspaNet = 0x374dcf1c
|
||||
|
||||
@@ -118,7 +118,6 @@ const (
|
||||
var bnStrings = map[KaspaNet]string{
|
||||
Mainnet: "Mainnet",
|
||||
Testnet: "Testnet",
|
||||
Regtest: "Regtest",
|
||||
Simnet: "Simnet",
|
||||
Devnet: "Devnet",
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package wire
|
||||
package appmessage
|
||||
|
||||
import "testing"
|
||||
|
||||
@@ -40,7 +40,6 @@ func TestKaspaNetStringer(t *testing.T) {
|
||||
want string
|
||||
}{
|
||||
{Mainnet, "Mainnet"},
|
||||
{Regtest, "Regtest"},
|
||||
{Testnet, "Testnet"},
|
||||
{Simnet, "Simnet"},
|
||||
{0xffffffff, "Unknown KaspaNet (4294967295)"},
|
||||
@@ -6,7 +6,7 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/logger"
|
||||
"github.com/kaspanet/kaspad/infrastructure/logger"
|
||||
"github.com/kaspanet/kaspad/util/panics"
|
||||
)
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
package blocklogger
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/logger"
|
||||
"github.com/kaspanet/kaspad/infrastructure/logger"
|
||||
)
|
||||
|
||||
var log, _ = logger.Get(logger.SubsystemTags.PROT)
|
||||
@@ -1,7 +1,7 @@
|
||||
package flowcontext
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/addressmanager"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/addressmanager"
|
||||
)
|
||||
|
||||
// AddressManager returns the address manager associated to the flow context.
|
||||
@@ -3,11 +3,11 @@ package flowcontext
|
||||
import (
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/kaspanet/kaspad/blockdag"
|
||||
"github.com/kaspanet/kaspad/protocol/flows/blockrelay"
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
"github.com/kaspanet/kaspad/app/protocol/flows/blockrelay"
|
||||
"github.com/kaspanet/kaspad/domain/blockdag"
|
||||
"github.com/kaspanet/kaspad/util"
|
||||
"github.com/kaspanet/kaspad/util/daghash"
|
||||
"github.com/kaspanet/kaspad/wire"
|
||||
)
|
||||
|
||||
// OnNewBlock updates the mempool after a new block arrival, and
|
||||
@@ -19,8 +19,6 @@ func (f *FlowContext) OnNewBlock(block *util.Block) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// TODO(libp2p) Notify transactionsAcceptedToMempool to RPC
|
||||
|
||||
return f.broadcastTransactionsAfterBlockAdded(block, transactionsAcceptedToMempool)
|
||||
}
|
||||
|
||||
@@ -41,16 +39,18 @@ func (f *FlowContext) broadcastTransactionsAfterBlockAdded(block *util.Block, tr
|
||||
for i, tx := range transactionsAcceptedToMempool {
|
||||
txIDsToBroadcast[i] = tx.ID()
|
||||
}
|
||||
|
||||
copy(txIDsToBroadcast[len(transactionsAcceptedToMempool):], txIDsToBroadcast)
|
||||
offset := len(transactionsAcceptedToMempool)
|
||||
for i, txID := range txIDsToRebroadcast {
|
||||
txIDsToBroadcast[offset+i] = txID
|
||||
}
|
||||
|
||||
if len(txIDsToBroadcast) == 0 {
|
||||
return nil
|
||||
}
|
||||
if len(txIDsToBroadcast) > wire.MaxInvPerTxInvMsg {
|
||||
txIDsToBroadcast = txIDsToBroadcast[:wire.MaxInvPerTxInvMsg]
|
||||
if len(txIDsToBroadcast) > appmessage.MaxInvPerTxInvMsg {
|
||||
txIDsToBroadcast = txIDsToBroadcast[:appmessage.MaxInvPerTxInvMsg]
|
||||
}
|
||||
inv := wire.NewMsgInvTransaction(txIDsToBroadcast)
|
||||
inv := appmessage.NewMsgInvTransaction(txIDsToBroadcast)
|
||||
return f.Broadcast(inv)
|
||||
}
|
||||
|
||||
@@ -66,5 +66,9 @@ func (f *FlowContext) AddBlock(block *util.Block, flags blockdag.BehaviorFlags)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return f.Broadcast(wire.NewMsgInvBlock(block.Hash()))
|
||||
err = f.OnNewBlock(block)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return f.Broadcast(appmessage.NewMsgInvBlock(block.Hash()))
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
package flowcontext
|
||||
|
||||
import "github.com/kaspanet/kaspad/config"
|
||||
import "github.com/kaspanet/kaspad/infrastructure/config"
|
||||
|
||||
// Config returns an instance of *config.Config associated to the flow context.
|
||||
func (f *FlowContext) Config() *config.Config {
|
||||
@@ -1,6 +1,6 @@
|
||||
package flowcontext
|
||||
|
||||
import "github.com/kaspanet/kaspad/blockdag"
|
||||
import "github.com/kaspanet/kaspad/domain/blockdag"
|
||||
|
||||
// DAG returns the DAG associated to the flow context.
|
||||
func (f *FlowContext) DAG() *blockdag.BlockDAG {
|
||||
31
app/protocol/flowcontext/errors.go
Normal file
31
app/protocol/flowcontext/errors.go
Normal file
@@ -0,0 +1,31 @@
|
||||
package flowcontext
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
||||
|
||||
"github.com/kaspanet/kaspad/app/protocol/protocolerrors"
|
||||
)
|
||||
|
||||
// HandleError handles an error from a flow,
|
||||
// It sends the error to errChan if isStopping == 0 and increments isStopping
|
||||
//
|
||||
// If this is ErrRouteClosed - forward it to errChan
|
||||
// If this is ProtocolError - logs the error, and forward it to errChan
|
||||
// Otherwise - panics
|
||||
func (*FlowContext) HandleError(err error, flowName string, isStopping *uint32, errChan chan<- error) {
|
||||
isErrRouteClosed := errors.Is(err, router.ErrRouteClosed)
|
||||
if !isErrRouteClosed {
|
||||
if protocolErr := &(protocolerrors.ProtocolError{}); !errors.As(err, &protocolErr) {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
log.Errorf("error from %s: %+v", flowName, err)
|
||||
}
|
||||
|
||||
if atomic.AddUint32(isStopping, 1) == 1 {
|
||||
errChan <- err
|
||||
}
|
||||
}
|
||||
@@ -4,16 +4,16 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/kaspanet/kaspad/addressmanager"
|
||||
"github.com/kaspanet/kaspad/blockdag"
|
||||
"github.com/kaspanet/kaspad/config"
|
||||
"github.com/kaspanet/kaspad/connmanager"
|
||||
"github.com/kaspanet/kaspad/mempool"
|
||||
"github.com/kaspanet/kaspad/netadapter"
|
||||
"github.com/kaspanet/kaspad/netadapter/id"
|
||||
"github.com/kaspanet/kaspad/protocol/flows/blockrelay"
|
||||
"github.com/kaspanet/kaspad/protocol/flows/relaytransactions"
|
||||
peerpkg "github.com/kaspanet/kaspad/protocol/peer"
|
||||
"github.com/kaspanet/kaspad/app/protocol/flows/blockrelay"
|
||||
"github.com/kaspanet/kaspad/app/protocol/flows/relaytransactions"
|
||||
peerpkg "github.com/kaspanet/kaspad/app/protocol/peer"
|
||||
"github.com/kaspanet/kaspad/domain/blockdag"
|
||||
"github.com/kaspanet/kaspad/domain/mempool"
|
||||
"github.com/kaspanet/kaspad/infrastructure/config"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/addressmanager"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/connmanager"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/id"
|
||||
"github.com/kaspanet/kaspad/util"
|
||||
"github.com/kaspanet/kaspad/util/daghash"
|
||||
)
|
||||
@@ -39,7 +39,7 @@ type FlowContext struct {
|
||||
startIBDMutex sync.Mutex
|
||||
ibdPeer *peerpkg.Peer
|
||||
|
||||
peers map[*id.ID]*peerpkg.Peer
|
||||
peers map[id.ID]*peerpkg.Peer
|
||||
peersMutex sync.RWMutex
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ func New(cfg *config.Config, dag *blockdag.BlockDAG, addressManager *addressmana
|
||||
txPool: txPool,
|
||||
sharedRequestedTransactions: relaytransactions.NewSharedRequestedTransactions(),
|
||||
sharedRequestedBlocks: blockrelay.NewSharedRequestedBlocks(),
|
||||
peers: make(map[*id.ID]*peerpkg.Peer),
|
||||
peers: make(map[id.ID]*peerpkg.Peer),
|
||||
transactionsToRebroadcast: make(map[daghash.TxID]*util.Tx),
|
||||
}
|
||||
}
|
||||
@@ -4,8 +4,8 @@ import (
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/kaspanet/kaspad/blockdag"
|
||||
peerpkg "github.com/kaspanet/kaspad/protocol/peer"
|
||||
peerpkg "github.com/kaspanet/kaspad/app/protocol/peer"
|
||||
"github.com/kaspanet/kaspad/domain/blockdag"
|
||||
)
|
||||
|
||||
// StartIBDIfRequired selects a peer and starts IBD against it
|
||||
@@ -37,6 +37,9 @@ func (f *FlowContext) IsInIBD() bool {
|
||||
// selectPeerForIBD returns the first peer whose selected tip
|
||||
// hash is not in our DAG
|
||||
func (f *FlowContext) selectPeerForIBD(dag *blockdag.BlockDAG) *peerpkg.Peer {
|
||||
f.peersMutex.RLock()
|
||||
defer f.peersMutex.RUnlock()
|
||||
|
||||
for _, peer := range f.peers {
|
||||
peerSelectedTipHash := peer.SelectedTipHash()
|
||||
if !dag.IsInDAG(peerSelectedTipHash) {
|
||||
@@ -59,6 +62,9 @@ func (f *FlowContext) isDAGTimeCurrent() bool {
|
||||
}
|
||||
|
||||
func (f *FlowContext) requestSelectedTips() {
|
||||
f.peersMutex.RLock()
|
||||
defer f.peersMutex.RUnlock()
|
||||
|
||||
for _, peer := range f.peers {
|
||||
peer.RequestSelectedTipIfRequired()
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
package flowcontext
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/logger"
|
||||
"github.com/kaspanet/kaspad/infrastructure/logger"
|
||||
"github.com/kaspanet/kaspad/util/panics"
|
||||
)
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package flowcontext
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/connmanager"
|
||||
"github.com/kaspanet/kaspad/netadapter"
|
||||
"github.com/kaspanet/kaspad/protocol/common"
|
||||
peerpkg "github.com/kaspanet/kaspad/protocol/peer"
|
||||
"github.com/kaspanet/kaspad/wire"
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
"github.com/kaspanet/kaspad/app/protocol/common"
|
||||
peerpkg "github.com/kaspanet/kaspad/app/protocol/peer"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/connmanager"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
@@ -24,15 +24,23 @@ func (f *FlowContext) AddToPeers(peer *peerpkg.Peer) error {
|
||||
f.peersMutex.Lock()
|
||||
defer f.peersMutex.Unlock()
|
||||
|
||||
if _, ok := f.peers[peer.ID()]; ok {
|
||||
if _, ok := f.peers[*peer.ID()]; ok {
|
||||
return errors.Wrapf(common.ErrPeerWithSameIDExists, "peer with ID %s already exists", peer.ID())
|
||||
}
|
||||
|
||||
f.peers[peer.ID()] = peer
|
||||
f.peers[*peer.ID()] = peer
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// RemoveFromPeers remove this peer from the peers list.
|
||||
func (f *FlowContext) RemoveFromPeers(peer *peerpkg.Peer) {
|
||||
f.peersMutex.Lock()
|
||||
defer f.peersMutex.Unlock()
|
||||
|
||||
delete(f.peers, *peer.ID())
|
||||
}
|
||||
|
||||
// readyPeerConnections returns the NetConnections of all the ready peers.
|
||||
func (f *FlowContext) readyPeerConnections() []*netadapter.NetConnection {
|
||||
f.peersMutex.RLock()
|
||||
@@ -47,7 +55,7 @@ func (f *FlowContext) readyPeerConnections() []*netadapter.NetConnection {
|
||||
}
|
||||
|
||||
// Broadcast broadcast the given message to all the ready peers.
|
||||
func (f *FlowContext) Broadcast(message wire.Message) error {
|
||||
func (f *FlowContext) Broadcast(message appmessage.Message) error {
|
||||
return f.netAdapter.Broadcast(f.readyPeerConnections(), message)
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package flowcontext
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/mempool"
|
||||
"github.com/kaspanet/kaspad/protocol/flows/relaytransactions"
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
"github.com/kaspanet/kaspad/app/protocol/flows/relaytransactions"
|
||||
"github.com/kaspanet/kaspad/domain/mempool"
|
||||
"github.com/kaspanet/kaspad/util"
|
||||
"github.com/kaspanet/kaspad/util/daghash"
|
||||
"github.com/kaspanet/kaspad/wire"
|
||||
"github.com/pkg/errors"
|
||||
"time"
|
||||
)
|
||||
@@ -15,7 +15,7 @@ func (f *FlowContext) AddTransaction(tx *util.Tx) error {
|
||||
f.transactionsToRebroadcastLock.Lock()
|
||||
defer f.transactionsToRebroadcastLock.Unlock()
|
||||
|
||||
transactionsAcceptedToMempool, err := f.txPool.ProcessTransaction(tx, false, 0)
|
||||
transactionsAcceptedToMempool, err := f.txPool.ProcessTransaction(tx, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -25,7 +25,7 @@ func (f *FlowContext) AddTransaction(tx *util.Tx) error {
|
||||
}
|
||||
|
||||
f.transactionsToRebroadcast[*tx.ID()] = tx
|
||||
inv := wire.NewMsgInvTransaction([]*daghash.TxID{tx.ID()})
|
||||
inv := appmessage.NewMsgInvTransaction([]*daghash.TxID{tx.ID()})
|
||||
return f.Broadcast(inv)
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
package addressexchange
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/addressmanager"
|
||||
"github.com/kaspanet/kaspad/config"
|
||||
"github.com/kaspanet/kaspad/netadapter/router"
|
||||
"github.com/kaspanet/kaspad/protocol/common"
|
||||
peerpkg "github.com/kaspanet/kaspad/protocol/peer"
|
||||
"github.com/kaspanet/kaspad/protocol/protocolerrors"
|
||||
"github.com/kaspanet/kaspad/wire"
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
"github.com/kaspanet/kaspad/app/protocol/common"
|
||||
peerpkg "github.com/kaspanet/kaspad/app/protocol/peer"
|
||||
"github.com/kaspanet/kaspad/app/protocol/protocolerrors"
|
||||
"github.com/kaspanet/kaspad/infrastructure/config"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/addressmanager"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
||||
)
|
||||
|
||||
// ReceiveAddressesContext is the interface for the context needed for the ReceiveAddresses flow.
|
||||
@@ -25,7 +25,7 @@ func ReceiveAddresses(context ReceiveAddressesContext, incomingRoute *router.Rou
|
||||
}
|
||||
|
||||
subnetworkID := peer.SubnetworkID()
|
||||
msgGetAddresses := wire.NewMsgRequestAddresses(false, subnetworkID)
|
||||
msgGetAddresses := appmessage.NewMsgRequestAddresses(false, subnetworkID)
|
||||
err := outgoingRoute.Enqueue(msgGetAddresses)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -36,9 +36,9 @@ func ReceiveAddresses(context ReceiveAddressesContext, incomingRoute *router.Rou
|
||||
return err
|
||||
}
|
||||
|
||||
msgAddresses := message.(*wire.MsgAddresses)
|
||||
msgAddresses := message.(*appmessage.MsgAddresses)
|
||||
if len(msgAddresses.AddrList) > addressmanager.GetAddressesMax {
|
||||
return protocolerrors.Errorf(true, "address count excceeded %d", addressmanager.GetAddressesMax)
|
||||
return protocolerrors.Errorf(true, "address count exceeded %d", addressmanager.GetAddressesMax)
|
||||
}
|
||||
|
||||
if msgAddresses.IncludeAllSubnetworks {
|
||||
@@ -51,9 +51,7 @@ func ReceiveAddresses(context ReceiveAddressesContext, incomingRoute *router.Rou
|
||||
context.Config().SubnetworkID, msgAddresses.Command(), msgAddresses.SubnetworkID)
|
||||
}
|
||||
|
||||
// TODO(libp2p) Consider adding to peer known addresses set
|
||||
// TODO(libp2p) Replace with real peer IP
|
||||
fakeSourceAddress := new(wire.NetAddress)
|
||||
context.AddressManager().AddAddresses(msgAddresses.AddrList, fakeSourceAddress, msgAddresses.SubnetworkID)
|
||||
sourceAddress := peer.Connection().NetAddress()
|
||||
context.AddressManager().AddAddresses(msgAddresses.AddrList, sourceAddress, msgAddresses.SubnetworkID)
|
||||
return nil
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
package addressexchange
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/addressmanager"
|
||||
"github.com/kaspanet/kaspad/netadapter/router"
|
||||
"github.com/kaspanet/kaspad/wire"
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/addressmanager"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
||||
"math/rand"
|
||||
)
|
||||
|
||||
@@ -14,16 +14,15 @@ type SendAddressesContext interface {
|
||||
|
||||
// SendAddresses sends addresses to a peer that requests it.
|
||||
func SendAddresses(context SendAddressesContext, incomingRoute *router.Route, outgoingRoute *router.Route) error {
|
||||
|
||||
message, err := incomingRoute.Dequeue()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
msgGetAddresses := message.(*wire.MsgRequestAddresses)
|
||||
msgGetAddresses := message.(*appmessage.MsgRequestAddresses)
|
||||
addresses := context.AddressManager().AddressCache(msgGetAddresses.IncludeAllSubnetworks,
|
||||
msgGetAddresses.SubnetworkID)
|
||||
msgAddresses := wire.NewMsgAddresses(msgGetAddresses.IncludeAllSubnetworks, msgGetAddresses.SubnetworkID)
|
||||
msgAddresses := appmessage.NewMsgAddresses(msgGetAddresses.IncludeAllSubnetworks, msgGetAddresses.SubnetworkID)
|
||||
err = msgAddresses.AddAddresses(shuffleAddresses(addresses)...)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -33,14 +32,14 @@ func SendAddresses(context SendAddressesContext, incomingRoute *router.Route, ou
|
||||
}
|
||||
|
||||
// shuffleAddresses randomizes the given addresses sent if there are more than the maximum allowed in one message.
|
||||
func shuffleAddresses(addresses []*wire.NetAddress) []*wire.NetAddress {
|
||||
func shuffleAddresses(addresses []*appmessage.NetAddress) []*appmessage.NetAddress {
|
||||
addressCount := len(addresses)
|
||||
|
||||
if addressCount < wire.MaxAddressesPerMsg {
|
||||
if addressCount < appmessage.MaxAddressesPerMsg {
|
||||
return addresses
|
||||
}
|
||||
|
||||
shuffleAddresses := make([]*wire.NetAddress, addressCount)
|
||||
shuffleAddresses := make([]*appmessage.NetAddress, addressCount)
|
||||
copy(shuffleAddresses, addresses)
|
||||
|
||||
rand.Shuffle(addressCount, func(i, j int) {
|
||||
@@ -48,6 +47,6 @@ func shuffleAddresses(addresses []*wire.NetAddress) []*wire.NetAddress {
|
||||
})
|
||||
|
||||
// Truncate it to the maximum size.
|
||||
shuffleAddresses = shuffleAddresses[:wire.MaxAddressesPerMsg]
|
||||
shuffleAddresses = shuffleAddresses[:appmessage.MaxAddressesPerMsg]
|
||||
return shuffleAddresses
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
package blockrelay
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/blockdag"
|
||||
"github.com/kaspanet/kaspad/netadapter/router"
|
||||
peerpkg "github.com/kaspanet/kaspad/protocol/peer"
|
||||
"github.com/kaspanet/kaspad/protocol/protocolerrors"
|
||||
"github.com/kaspanet/kaspad/wire"
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
peerpkg "github.com/kaspanet/kaspad/app/protocol/peer"
|
||||
"github.com/kaspanet/kaspad/app/protocol/protocolerrors"
|
||||
"github.com/kaspanet/kaspad/domain/blockdag"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
@@ -14,7 +14,7 @@ type RelayBlockRequestsContext interface {
|
||||
DAG() *blockdag.BlockDAG
|
||||
}
|
||||
|
||||
// HandleRelayBlockRequests listens to wire.MsgRequestRelayBlocks messages and sends
|
||||
// HandleRelayBlockRequests listens to appmessage.MsgRequestRelayBlocks messages and sends
|
||||
// their corresponding blocks to the requesting peer.
|
||||
func HandleRelayBlockRequests(context RelayBlockRequestsContext, incomingRoute *router.Route,
|
||||
outgoingRoute *router.Route, peer *peerpkg.Peer) error {
|
||||
@@ -24,7 +24,7 @@ func HandleRelayBlockRequests(context RelayBlockRequestsContext, incomingRoute *
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
getRelayBlocksMessage := message.(*wire.MsgRequestRelayBlocks)
|
||||
getRelayBlocksMessage := message.(*appmessage.MsgRequestRelayBlocks)
|
||||
for _, hash := range getRelayBlocksMessage.Hashes {
|
||||
// Fetch the block from the database.
|
||||
block, err := context.DAG().BlockByHash(hash)
|
||||
@@ -1,17 +1,17 @@
|
||||
package blockrelay
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/blockdag"
|
||||
"github.com/kaspanet/kaspad/netadapter"
|
||||
"github.com/kaspanet/kaspad/netadapter/router"
|
||||
"github.com/kaspanet/kaspad/protocol/blocklogger"
|
||||
"github.com/kaspanet/kaspad/protocol/common"
|
||||
peerpkg "github.com/kaspanet/kaspad/protocol/peer"
|
||||
"github.com/kaspanet/kaspad/protocol/protocolerrors"
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
"github.com/kaspanet/kaspad/app/protocol/blocklogger"
|
||||
"github.com/kaspanet/kaspad/app/protocol/common"
|
||||
peerpkg "github.com/kaspanet/kaspad/app/protocol/peer"
|
||||
"github.com/kaspanet/kaspad/app/protocol/protocolerrors"
|
||||
"github.com/kaspanet/kaspad/domain/blockdag"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
||||
"github.com/kaspanet/kaspad/util"
|
||||
"github.com/kaspanet/kaspad/util/daghash"
|
||||
mathUtil "github.com/kaspanet/kaspad/util/math"
|
||||
"github.com/kaspanet/kaspad/wire"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
@@ -23,17 +23,17 @@ type RelayInvsContext interface {
|
||||
SharedRequestedBlocks() *SharedRequestedBlocks
|
||||
StartIBDIfRequired()
|
||||
IsInIBD() bool
|
||||
Broadcast(message wire.Message) error
|
||||
Broadcast(message appmessage.Message) error
|
||||
}
|
||||
|
||||
type handleRelayInvsFlow struct {
|
||||
RelayInvsContext
|
||||
incomingRoute, outgoingRoute *router.Route
|
||||
peer *peerpkg.Peer
|
||||
invsQueue []*wire.MsgInvRelayBlock
|
||||
invsQueue []*appmessage.MsgInvRelayBlock
|
||||
}
|
||||
|
||||
// HandleRelayInvs listens to wire.MsgInvRelayBlock messages, requests their corresponding blocks if they
|
||||
// HandleRelayInvs listens to appmessage.MsgInvRelayBlock messages, requests their corresponding blocks if they
|
||||
// are missing, adds them to the DAG and propagates them to the rest of the network.
|
||||
func HandleRelayInvs(context RelayInvsContext, incomingRoute *router.Route, outgoingRoute *router.Route,
|
||||
peer *peerpkg.Peer) error {
|
||||
@@ -43,7 +43,7 @@ func HandleRelayInvs(context RelayInvsContext, incomingRoute *router.Route, outg
|
||||
incomingRoute: incomingRoute,
|
||||
outgoingRoute: outgoingRoute,
|
||||
peer: peer,
|
||||
invsQueue: make([]*wire.MsgInvRelayBlock, 0),
|
||||
invsQueue: make([]*appmessage.MsgInvRelayBlock, 0),
|
||||
}
|
||||
return flow.start()
|
||||
}
|
||||
@@ -55,6 +55,8 @@ func (flow *handleRelayInvsFlow) start() error {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Debugf("Got relay inv for block %s", inv.Hash)
|
||||
|
||||
if flow.DAG().IsKnownBlock(inv.Hash) {
|
||||
if flow.DAG().IsKnownInvalid(inv.Hash) {
|
||||
return protocolerrors.Errorf(true, "sent inv of an invalid block %s",
|
||||
@@ -81,10 +83,10 @@ func (flow *handleRelayInvsFlow) start() error {
|
||||
}
|
||||
}
|
||||
|
||||
func (flow *handleRelayInvsFlow) readInv() (*wire.MsgInvRelayBlock, error) {
|
||||
func (flow *handleRelayInvsFlow) readInv() (*appmessage.MsgInvRelayBlock, error) {
|
||||
|
||||
if len(flow.invsQueue) > 0 {
|
||||
var inv *wire.MsgInvRelayBlock
|
||||
var inv *appmessage.MsgInvRelayBlock
|
||||
inv, flow.invsQueue = flow.invsQueue[0], flow.invsQueue[1:]
|
||||
return inv, nil
|
||||
}
|
||||
@@ -94,7 +96,7 @@ func (flow *handleRelayInvsFlow) readInv() (*wire.MsgInvRelayBlock, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
inv, ok := msg.(*wire.MsgInvRelayBlock)
|
||||
inv, ok := msg.(*appmessage.MsgInvRelayBlock)
|
||||
if !ok {
|
||||
return nil, protocolerrors.Errorf(true, "unexpected %s message in the block relay handleRelayInvsFlow while "+
|
||||
"expecting an inv message", msg.Command())
|
||||
@@ -103,7 +105,7 @@ func (flow *handleRelayInvsFlow) readInv() (*wire.MsgInvRelayBlock, error) {
|
||||
}
|
||||
|
||||
func (flow *handleRelayInvsFlow) requestBlocks(requestQueue *hashesQueueSet) error {
|
||||
numHashesToRequest := mathUtil.MinInt(wire.MsgRequestRelayBlocksHashes, requestQueue.len())
|
||||
numHashesToRequest := mathUtil.MinInt(appmessage.MsgRequestRelayBlocksHashes, requestQueue.len())
|
||||
hashesToRequest := requestQueue.dequeue(numHashesToRequest)
|
||||
|
||||
pendingBlocks := map[daghash.Hash]struct{}{}
|
||||
@@ -114,6 +116,11 @@ func (flow *handleRelayInvsFlow) requestBlocks(requestQueue *hashesQueueSet) err
|
||||
continue
|
||||
}
|
||||
|
||||
// The block can become known from another peer in the process of orphan resolution
|
||||
if flow.DAG().IsKnownBlock(hash) {
|
||||
continue
|
||||
}
|
||||
|
||||
pendingBlocks[*hash] = struct{}{}
|
||||
filteredHashesToRequest = append(filteredHashesToRequest, hash)
|
||||
}
|
||||
@@ -127,7 +134,7 @@ func (flow *handleRelayInvsFlow) requestBlocks(requestQueue *hashesQueueSet) err
|
||||
// clean from any pending blocks.
|
||||
defer flow.SharedRequestedBlocks().removeSet(pendingBlocks)
|
||||
|
||||
getRelayBlocksMsg := wire.NewMsgRequestRelayBlocks(filteredHashesToRequest)
|
||||
getRelayBlocksMsg := appmessage.NewMsgRequestRelayBlocks(filteredHashesToRequest)
|
||||
err := flow.outgoingRoute.Enqueue(getRelayBlocksMsg)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -153,16 +160,15 @@ func (flow *handleRelayInvsFlow) requestBlocks(requestQueue *hashesQueueSet) err
|
||||
|
||||
delete(pendingBlocks, *blockHash)
|
||||
flow.SharedRequestedBlocks().remove(blockHash)
|
||||
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// readMsgBlock returns the next msgBlock in msgChan, and populates invsQueue with any inv messages that meanwhile arrive.
|
||||
//
|
||||
// Note: this function assumes msgChan can contain only wire.MsgInvRelayBlock and wire.MsgBlock messages.
|
||||
// Note: this function assumes msgChan can contain only appmessage.MsgInvRelayBlock and appmessage.MsgBlock messages.
|
||||
func (flow *handleRelayInvsFlow) readMsgBlock() (
|
||||
msgBlock *wire.MsgBlock, err error) {
|
||||
msgBlock *appmessage.MsgBlock, err error) {
|
||||
|
||||
for {
|
||||
message, err := flow.incomingRoute.DequeueWithTimeout(common.DefaultTimeout)
|
||||
@@ -171,9 +177,9 @@ func (flow *handleRelayInvsFlow) readMsgBlock() (
|
||||
}
|
||||
|
||||
switch message := message.(type) {
|
||||
case *wire.MsgInvRelayBlock:
|
||||
case *appmessage.MsgInvRelayBlock:
|
||||
flow.invsQueue = append(flow.invsQueue, message)
|
||||
case *wire.MsgBlock:
|
||||
case *appmessage.MsgBlock:
|
||||
return message, nil
|
||||
default:
|
||||
return nil, errors.Errorf("unexpected message %s", message.Command())
|
||||
@@ -190,7 +196,7 @@ func (flow *handleRelayInvsFlow) processAndRelayBlock(requestQueue *hashesQueueS
|
||||
}
|
||||
log.Infof("Rejected block %s from %s: %s", blockHash, flow.peer, err)
|
||||
|
||||
return protocolerrors.Wrap(true, err, "got invalid block")
|
||||
return protocolerrors.Wrapf(true, err, "got invalid block %s from relay", blockHash)
|
||||
}
|
||||
|
||||
if isDelayed {
|
||||
@@ -224,13 +230,7 @@ func (flow *handleRelayInvsFlow) processAndRelayBlock(requestQueue *hashesQueueS
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
//TODO(libp2p)
|
||||
//// When the block is not an orphan, log information about it and
|
||||
//// update the DAG state.
|
||||
// sm.restartSyncIfNeeded()
|
||||
//// Clear the rejected transactions.
|
||||
//sm.rejectedTxns = make(map[daghash.TxID]struct{})
|
||||
err = flow.Broadcast(wire.NewMsgInvBlock(blockHash))
|
||||
err = flow.Broadcast(appmessage.NewMsgInvBlock(blockHash))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
package blockrelay
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/logger"
|
||||
"github.com/kaspanet/kaspad/infrastructure/logger"
|
||||
"github.com/kaspanet/kaspad/util/panics"
|
||||
)
|
||||
|
||||
@@ -4,19 +4,18 @@ import (
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/kaspanet/kaspad/addressmanager"
|
||||
"github.com/kaspanet/kaspad/protocol/common"
|
||||
"github.com/kaspanet/kaspad/protocol/protocolerrors"
|
||||
"github.com/kaspanet/kaspad/app/protocol/common"
|
||||
"github.com/kaspanet/kaspad/app/protocol/protocolerrors"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/addressmanager"
|
||||
|
||||
"github.com/kaspanet/kaspad/blockdag"
|
||||
"github.com/kaspanet/kaspad/config"
|
||||
"github.com/kaspanet/kaspad/netadapter"
|
||||
"github.com/kaspanet/kaspad/domain/blockdag"
|
||||
"github.com/kaspanet/kaspad/infrastructure/config"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter"
|
||||
|
||||
"github.com/kaspanet/kaspad/netadapter/router"
|
||||
routerpkg "github.com/kaspanet/kaspad/netadapter/router"
|
||||
peerpkg "github.com/kaspanet/kaspad/protocol/peer"
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
peerpkg "github.com/kaspanet/kaspad/app/protocol/peer"
|
||||
routerpkg "github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
||||
"github.com/kaspanet/kaspad/util/locks"
|
||||
"github.com/kaspanet/kaspad/wire"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
@@ -35,7 +34,7 @@ type HandleHandshakeContext interface {
|
||||
// version message, as well as a verack for the sent version
|
||||
func HandleHandshake(context HandleHandshakeContext, netConnection *netadapter.NetConnection,
|
||||
receiveVersionRoute *routerpkg.Route, sendVersionRoute *routerpkg.Route, outgoingRoute *routerpkg.Route,
|
||||
) (peer *peerpkg.Peer, err error) {
|
||||
) (*peerpkg.Peer, error) {
|
||||
|
||||
// For HandleHandshake to finish, we need to get from the other node
|
||||
// a version and verack messages, so we increase the wait group by 2
|
||||
@@ -46,26 +45,26 @@ func HandleHandshake(context HandleHandshakeContext, netConnection *netadapter.N
|
||||
isStopping := uint32(0)
|
||||
errChan := make(chan error)
|
||||
|
||||
peer = peerpkg.New(netConnection)
|
||||
peer := peerpkg.New(netConnection)
|
||||
|
||||
var peerAddress *wire.NetAddress
|
||||
var peerAddress *appmessage.NetAddress
|
||||
spawn("HandleHandshake-ReceiveVersion", func() {
|
||||
defer wg.Done()
|
||||
address, err := ReceiveVersion(context, receiveVersionRoute, outgoingRoute, peer)
|
||||
if err != nil {
|
||||
handleError(err, "ReceiveVersion", &isStopping, errChan)
|
||||
return
|
||||
}
|
||||
peerAddress = address
|
||||
wg.Done()
|
||||
})
|
||||
|
||||
spawn("HandleHandshake-SendVersion", func() {
|
||||
defer wg.Done()
|
||||
err := SendVersion(context, sendVersionRoute, outgoingRoute)
|
||||
err := SendVersion(context, sendVersionRoute, outgoingRoute, peer)
|
||||
if err != nil {
|
||||
handleError(err, "SendVersion", &isStopping, errChan)
|
||||
return
|
||||
}
|
||||
wg.Done()
|
||||
})
|
||||
|
||||
select {
|
||||
@@ -77,7 +76,7 @@ func HandleHandshake(context HandleHandshakeContext, netConnection *netadapter.N
|
||||
case <-locks.ReceiveFromChanWhenDone(func() { wg.Wait() }):
|
||||
}
|
||||
|
||||
err = context.AddToPeers(peer)
|
||||
err := context.AddToPeers(peer)
|
||||
if err != nil {
|
||||
if errors.As(err, &common.ErrPeerWithSameIDExists) {
|
||||
return nil, protocolerrors.Wrap(false, err, "peer already exists")
|
||||
@@ -99,7 +98,7 @@ func HandleHandshake(context HandleHandshakeContext, netConnection *netadapter.N
|
||||
// Handshake is different from other flows, since in it should forward router.ErrRouteClosed to errChan
|
||||
// Therefore we implement a separate handleError for handshake
|
||||
func handleError(err error, flowName string, isStopping *uint32, errChan chan error) {
|
||||
if errors.Is(err, router.ErrRouteClosed) {
|
||||
if errors.Is(err, routerpkg.ErrRouteClosed) {
|
||||
if atomic.AddUint32(isStopping, 1) == 1 {
|
||||
errChan <- err
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
package handshake
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/logger"
|
||||
"github.com/kaspanet/kaspad/infrastructure/logger"
|
||||
"github.com/kaspanet/kaspad/util/panics"
|
||||
)
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package handshake
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/netadapter/router"
|
||||
"github.com/kaspanet/kaspad/protocol/common"
|
||||
peerpkg "github.com/kaspanet/kaspad/protocol/peer"
|
||||
"github.com/kaspanet/kaspad/protocol/protocolerrors"
|
||||
"github.com/kaspanet/kaspad/wire"
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
"github.com/kaspanet/kaspad/app/protocol/common"
|
||||
peerpkg "github.com/kaspanet/kaspad/app/protocol/peer"
|
||||
"github.com/kaspanet/kaspad/app/protocol/protocolerrors"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -16,7 +16,7 @@ var (
|
||||
|
||||
// minAcceptableProtocolVersion is the lowest protocol version that a
|
||||
// connected peer may support.
|
||||
minAcceptableProtocolVersion = wire.ProtocolVersion
|
||||
minAcceptableProtocolVersion = appmessage.ProtocolVersion
|
||||
)
|
||||
|
||||
type receiveVersionFlow struct {
|
||||
@@ -28,7 +28,7 @@ type receiveVersionFlow struct {
|
||||
// ReceiveVersion waits for the peer to send a version message, sends a
|
||||
// verack in response, and updates its info accordingly.
|
||||
func ReceiveVersion(context HandleHandshakeContext, incomingRoute *router.Route, outgoingRoute *router.Route,
|
||||
peer *peerpkg.Peer) (*wire.NetAddress, error) {
|
||||
peer *peerpkg.Peer) (*appmessage.NetAddress, error) {
|
||||
|
||||
flow := &receiveVersionFlow{
|
||||
HandleHandshakeContext: context,
|
||||
@@ -40,13 +40,13 @@ func ReceiveVersion(context HandleHandshakeContext, incomingRoute *router.Route,
|
||||
return flow.start()
|
||||
}
|
||||
|
||||
func (flow *receiveVersionFlow) start() (*wire.NetAddress, error) {
|
||||
func (flow *receiveVersionFlow) start() (*appmessage.NetAddress, error) {
|
||||
message, err := flow.incomingRoute.DequeueWithTimeout(common.DefaultTimeout)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
msgVersion, ok := message.(*wire.MsgVersion)
|
||||
msgVersion, ok := message.(*appmessage.MsgVersion)
|
||||
if !ok {
|
||||
return nil, protocolerrors.New(true, "a version message must precede all others")
|
||||
}
|
||||
@@ -55,14 +55,18 @@ func (flow *receiveVersionFlow) start() (*wire.NetAddress, error) {
|
||||
return nil, protocolerrors.New(true, "connected to self")
|
||||
}
|
||||
|
||||
// Disconnect and ban peers from a different network
|
||||
if msgVersion.Network != flow.Config().ActiveNetParams.Name {
|
||||
return nil, protocolerrors.Errorf(true, "wrong network")
|
||||
}
|
||||
|
||||
// Notify and disconnect clients that have a protocol version that is
|
||||
// too old.
|
||||
//
|
||||
// NOTE: If minAcceptableProtocolVersion is raised to be higher than
|
||||
// wire.RejectVersion, this should send a reject packet before
|
||||
// appmessage.RejectVersion, this should send a reject packet before
|
||||
// disconnecting.
|
||||
if msgVersion.ProtocolVersion < minAcceptableProtocolVersion {
|
||||
//TODO(libp2p) create error type for disconnect but don't ban
|
||||
return nil, protocolerrors.Errorf(false, "protocol version must be %d or greater",
|
||||
minAcceptableProtocolVersion)
|
||||
}
|
||||
@@ -72,21 +76,21 @@ func (flow *receiveVersionFlow) start() (*wire.NetAddress, error) {
|
||||
return nil, protocolerrors.New(true, "partial nodes are not allowed")
|
||||
}
|
||||
|
||||
// TODO(libp2p)
|
||||
//// Disconnect if:
|
||||
//// - we are a full node and the outbound connection we've initiated is a partial node
|
||||
//// - the remote node is partial and our subnetwork doesn't match their subnetwork
|
||||
//localSubnetworkID := config.ActiveConfig().SubnetworkID
|
||||
//isLocalNodeFull := localSubnetworkID == nil
|
||||
//isRemoteNodeFull := msgVersion.SubnetworkID == nil
|
||||
//if (isLocalNodeFull && !isRemoteNodeFull && !connection.IsInbound()) ||
|
||||
// (!isLocalNodeFull && !isRemoteNodeFull && !msgVersion.SubnetworkID.IsEqual(localSubnetworkID)) {
|
||||
//
|
||||
// return nil, false, errors.New("incompatible subnetworks")
|
||||
//}
|
||||
// Disconnect if:
|
||||
// - we are a full node and the outbound connection we've initiated is a partial node
|
||||
// - the remote node is partial and our subnetwork doesn't match their subnetwork
|
||||
localSubnetworkID := flow.Config().SubnetworkID
|
||||
isLocalNodeFull := localSubnetworkID == nil
|
||||
isRemoteNodeFull := msgVersion.SubnetworkID == nil
|
||||
isOutbound := flow.peer.Connection().IsOutbound()
|
||||
if (isLocalNodeFull && !isRemoteNodeFull && isOutbound) ||
|
||||
(!isLocalNodeFull && !isRemoteNodeFull && !msgVersion.SubnetworkID.IsEqual(localSubnetworkID)) {
|
||||
|
||||
return nil, protocolerrors.New(false, "incompatible subnetworks")
|
||||
}
|
||||
|
||||
flow.peer.UpdateFieldsFromMsgVersion(msgVersion)
|
||||
err = flow.outgoingRoute.Enqueue(wire.NewMsgVerAck())
|
||||
err = flow.outgoingRoute.Enqueue(appmessage.NewMsgVerAck())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -1,10 +1,11 @@
|
||||
package handshake
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/netadapter/router"
|
||||
"github.com/kaspanet/kaspad/protocol/common"
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
"github.com/kaspanet/kaspad/app/protocol/common"
|
||||
peerpkg "github.com/kaspanet/kaspad/app/protocol/peer"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
||||
"github.com/kaspanet/kaspad/version"
|
||||
"github.com/kaspanet/kaspad/wire"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -18,24 +19,28 @@ var (
|
||||
|
||||
// defaultServices describes the default services that are supported by
|
||||
// the server.
|
||||
defaultServices = wire.SFNodeNetwork | wire.SFNodeBloom | wire.SFNodeCF
|
||||
defaultServices = appmessage.DefaultServices
|
||||
|
||||
// defaultRequiredServices describes the default services that are
|
||||
// required to be supported by outbound peers.
|
||||
defaultRequiredServices = wire.SFNodeNetwork
|
||||
defaultRequiredServices = appmessage.SFNodeNetwork
|
||||
)
|
||||
|
||||
type sendVersionFlow struct {
|
||||
HandleHandshakeContext
|
||||
incomingRoute, outgoingRoute *router.Route
|
||||
peer *peerpkg.Peer
|
||||
}
|
||||
|
||||
// SendVersion sends a version to a peer and waits for verack.
|
||||
func SendVersion(context HandleHandshakeContext, incomingRoute *router.Route, outgoingRoute *router.Route) error {
|
||||
func SendVersion(context HandleHandshakeContext, incomingRoute *router.Route,
|
||||
outgoingRoute *router.Route, peer *peerpkg.Peer) error {
|
||||
|
||||
flow := &sendVersionFlow{
|
||||
HandleHandshakeContext: context,
|
||||
incomingRoute: incomingRoute,
|
||||
outgoingRoute: outgoingRoute,
|
||||
peer: peer,
|
||||
}
|
||||
return flow.start()
|
||||
}
|
||||
@@ -45,23 +50,21 @@ func (flow *sendVersionFlow) start() error {
|
||||
subnetworkID := flow.Config().SubnetworkID
|
||||
|
||||
// Version message.
|
||||
localAddress, err := flow.NetAdapter().GetBestLocalAddress()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
msg := wire.NewMsgVersion(localAddress, flow.NetAdapter().ID(), selectedTipHash, subnetworkID)
|
||||
localAddress := flow.AddressManager().GetBestLocalAddress(flow.peer.Connection().NetAddress())
|
||||
msg := appmessage.NewMsgVersion(localAddress, flow.NetAdapter().ID(),
|
||||
flow.Config().ActiveNetParams.Name, selectedTipHash, subnetworkID)
|
||||
msg.AddUserAgent(userAgentName, userAgentVersion, flow.Config().UserAgentComments...)
|
||||
|
||||
// Advertise the services flag
|
||||
msg.Services = defaultServices
|
||||
|
||||
// Advertise our max supported protocol version.
|
||||
msg.ProtocolVersion = wire.ProtocolVersion
|
||||
msg.ProtocolVersion = appmessage.ProtocolVersion
|
||||
|
||||
// Advertise if inv messages for transactions are desired.
|
||||
msg.DisableRelayTx = flow.Config().BlocksOnly
|
||||
|
||||
err = flow.outgoingRoute.Enqueue(msg)
|
||||
err := flow.outgoingRoute.Enqueue(msg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
package ibd
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/blockdag"
|
||||
"github.com/kaspanet/kaspad/netadapter/router"
|
||||
"github.com/kaspanet/kaspad/protocol/protocolerrors"
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
"github.com/kaspanet/kaspad/app/protocol/protocolerrors"
|
||||
"github.com/kaspanet/kaspad/domain/blockdag"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
||||
"github.com/kaspanet/kaspad/util/daghash"
|
||||
"github.com/kaspanet/kaspad/wire"
|
||||
)
|
||||
|
||||
// RequestBlockLocatorContext is the interface for the context needed for the HandleRequestBlockLocator flow.
|
||||
@@ -57,13 +57,13 @@ func (flow *handleRequestBlockLocatorFlow) receiveGetBlockLocator() (lowHash *da
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
msgGetBlockLocator := message.(*wire.MsgRequestBlockLocator)
|
||||
msgGetBlockLocator := message.(*appmessage.MsgRequestBlockLocator)
|
||||
|
||||
return msgGetBlockLocator.LowHash, msgGetBlockLocator.HighHash, nil
|
||||
}
|
||||
|
||||
func (flow *handleRequestBlockLocatorFlow) sendBlockLocator(locator blockdag.BlockLocator) error {
|
||||
msgBlockLocator := wire.NewMsgBlockLocator(locator)
|
||||
msgBlockLocator := appmessage.NewMsgBlockLocator(locator)
|
||||
err := flow.outgoingRoute.Enqueue(msgBlockLocator)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -1,11 +1,12 @@
|
||||
package ibd
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/blockdag"
|
||||
"github.com/kaspanet/kaspad/netadapter/router"
|
||||
"github.com/kaspanet/kaspad/protocol/protocolerrors"
|
||||
"errors"
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
"github.com/kaspanet/kaspad/app/protocol/protocolerrors"
|
||||
"github.com/kaspanet/kaspad/domain/blockdag"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
||||
"github.com/kaspanet/kaspad/util/daghash"
|
||||
"github.com/kaspanet/kaspad/wire"
|
||||
)
|
||||
|
||||
const ibdBatchSize = router.DefaultMaxMessages
|
||||
@@ -65,12 +66,12 @@ func (flow *handleRequestBlocksFlow) start() error {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, ok := message.(*wire.MsgRequestNextIBDBlocks); !ok {
|
||||
if _, ok := message.(*appmessage.MsgRequestNextIBDBlocks); !ok {
|
||||
return protocolerrors.Errorf(true, "received unexpected message type. "+
|
||||
"expected: %s, got: %s", wire.CmdRequestNextIBDBlocks, message.Command())
|
||||
"expected: %s, got: %s", appmessage.CmdRequestNextIBDBlocks, message.Command())
|
||||
}
|
||||
}
|
||||
err = flow.outgoingRoute.Enqueue(wire.NewMsgDoneIBDBlocks())
|
||||
err = flow.outgoingRoute.Enqueue(appmessage.NewMsgDoneIBDBlocks())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -84,33 +85,37 @@ func receiveRequestIBDBlocks(incomingRoute *router.Route) (lowHash *daghash.Hash
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
msgRequestIBDBlocks := message.(*wire.MsgRequestIBDBlocks)
|
||||
msgRequestIBDBlocks := message.(*appmessage.MsgRequestIBDBlocks)
|
||||
|
||||
return msgRequestIBDBlocks.LowHash, msgRequestIBDBlocks.HighHash, nil
|
||||
}
|
||||
|
||||
func (flow *handleRequestBlocksFlow) buildMsgIBDBlocks(lowHash *daghash.Hash,
|
||||
highHash *daghash.Hash) ([]*wire.MsgIBDBlock, error) {
|
||||
highHash *daghash.Hash) ([]*appmessage.MsgIBDBlock, error) {
|
||||
|
||||
const maxHashesInMsgIBDBlocks = wire.MaxInvPerMsg
|
||||
const maxHashesInMsgIBDBlocks = appmessage.MaxInvPerMsg
|
||||
blockHashes, err := flow.DAG().AntiPastHashesBetween(lowHash, highHash, maxHashesInMsgIBDBlocks)
|
||||
if err != nil {
|
||||
if errors.Is(err, blockdag.ErrInvalidParameter) {
|
||||
return nil, protocolerrors.Wrapf(true, err, "could not get antiPast between "+
|
||||
"%s and %s", lowHash, highHash)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
msgIBDBlocks := make([]*wire.MsgIBDBlock, len(blockHashes))
|
||||
msgIBDBlocks := make([]*appmessage.MsgIBDBlock, len(blockHashes))
|
||||
for i, blockHash := range blockHashes {
|
||||
block, err := flow.DAG().BlockByHash(blockHash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
msgIBDBlocks[i] = wire.NewMsgIBDBlock(block.MsgBlock())
|
||||
msgIBDBlocks[i] = appmessage.NewMsgIBDBlock(block.MsgBlock())
|
||||
}
|
||||
|
||||
return msgIBDBlocks, nil
|
||||
}
|
||||
|
||||
func (flow *handleRequestBlocksFlow) sendMsgIBDBlocks(msgIBDBlocks []*wire.MsgIBDBlock) error {
|
||||
func (flow *handleRequestBlocksFlow) sendMsgIBDBlocks(msgIBDBlocks []*appmessage.MsgIBDBlock) error {
|
||||
for _, msgIBDBlock := range msgIBDBlocks {
|
||||
err := flow.outgoingRoute.Enqueue(msgIBDBlock)
|
||||
if err != nil {
|
||||
@@ -1,14 +1,16 @@
|
||||
package ibd
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/blockdag"
|
||||
"github.com/kaspanet/kaspad/netadapter/router"
|
||||
"github.com/kaspanet/kaspad/protocol/common"
|
||||
peerpkg "github.com/kaspanet/kaspad/protocol/peer"
|
||||
"github.com/kaspanet/kaspad/protocol/protocolerrors"
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
"github.com/kaspanet/kaspad/app/protocol/blocklogger"
|
||||
"github.com/kaspanet/kaspad/app/protocol/common"
|
||||
peerpkg "github.com/kaspanet/kaspad/app/protocol/peer"
|
||||
"github.com/kaspanet/kaspad/app/protocol/protocolerrors"
|
||||
"github.com/kaspanet/kaspad/domain/blockdag"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
||||
"github.com/kaspanet/kaspad/util"
|
||||
"github.com/kaspanet/kaspad/util/daghash"
|
||||
"github.com/kaspanet/kaspad/wire"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// HandleIBDContext is the interface for the context needed for the HandleIBD flow.
|
||||
@@ -52,10 +54,13 @@ func (flow *handleIBDFlow) runIBD() error {
|
||||
defer flow.FinishIBD()
|
||||
|
||||
peerSelectedTipHash := flow.peer.SelectedTipHash()
|
||||
log.Debugf("Trying to find highest shared chain block with peer %s with selected tip %s", flow.peer, peerSelectedTipHash)
|
||||
highestSharedBlockHash, err := flow.findHighestSharedBlockHash(peerSelectedTipHash)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Debugf("Found highest shared chain block %s with peer %s", highestSharedBlockHash, flow.peer)
|
||||
if flow.DAG().IsKnownFinalizedBlock(highestSharedBlockHash) {
|
||||
return protocolerrors.Errorf(false, "cannot initiate "+
|
||||
"IBD with peer %s because the highest shared chain block (%s) is "+
|
||||
@@ -96,7 +101,7 @@ func (flow *handleIBDFlow) findHighestSharedBlockHash(peerSelectedTipHash *dagha
|
||||
|
||||
func (flow *handleIBDFlow) sendGetBlockLocator(lowHash *daghash.Hash, highHash *daghash.Hash) error {
|
||||
|
||||
msgGetBlockLocator := wire.NewMsgRequestBlockLocator(highHash, lowHash)
|
||||
msgGetBlockLocator := appmessage.NewMsgRequestBlockLocator(highHash, lowHash)
|
||||
return flow.outgoingRoute.Enqueue(msgGetBlockLocator)
|
||||
}
|
||||
|
||||
@@ -105,11 +110,11 @@ func (flow *handleIBDFlow) receiveBlockLocator() (blockLocatorHashes []*daghash.
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
msgBlockLocator, ok := message.(*wire.MsgBlockLocator)
|
||||
msgBlockLocator, ok := message.(*appmessage.MsgBlockLocator)
|
||||
if !ok {
|
||||
return nil,
|
||||
protocolerrors.Errorf(true, "received unexpected message type. "+
|
||||
"expected: %s, got: %s", wire.CmdBlockLocator, message.Command())
|
||||
"expected: %s, got: %s", appmessage.CmdBlockLocator, message.Command())
|
||||
}
|
||||
return msgBlockLocator.BlockLocatorHashes, nil
|
||||
}
|
||||
@@ -140,7 +145,7 @@ func (flow *handleIBDFlow) downloadBlocks(highestSharedBlockHash *daghash.Hash,
|
||||
|
||||
blocksReceived++
|
||||
if blocksReceived%ibdBatchSize == 0 {
|
||||
err = flow.outgoingRoute.Enqueue(wire.NewMsgRequestNextIBDBlocks())
|
||||
err = flow.outgoingRoute.Enqueue(appmessage.NewMsgRequestNextIBDBlocks())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -151,36 +156,41 @@ func (flow *handleIBDFlow) downloadBlocks(highestSharedBlockHash *daghash.Hash,
|
||||
func (flow *handleIBDFlow) sendGetBlocks(highestSharedBlockHash *daghash.Hash,
|
||||
peerSelectedTipHash *daghash.Hash) error {
|
||||
|
||||
msgGetBlockInvs := wire.NewMsgRequstIBDBlocks(highestSharedBlockHash, peerSelectedTipHash)
|
||||
msgGetBlockInvs := appmessage.NewMsgRequstIBDBlocks(highestSharedBlockHash, peerSelectedTipHash)
|
||||
return flow.outgoingRoute.Enqueue(msgGetBlockInvs)
|
||||
}
|
||||
|
||||
func (flow *handleIBDFlow) receiveIBDBlock() (msgIBDBlock *wire.MsgIBDBlock, doneIBD bool, err error) {
|
||||
func (flow *handleIBDFlow) receiveIBDBlock() (msgIBDBlock *appmessage.MsgIBDBlock, doneIBD bool, err error) {
|
||||
message, err := flow.incomingRoute.DequeueWithTimeout(common.DefaultTimeout)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
switch message := message.(type) {
|
||||
case *wire.MsgIBDBlock:
|
||||
case *appmessage.MsgIBDBlock:
|
||||
return message, false, nil
|
||||
case *wire.MsgDoneIBDBlocks:
|
||||
case *appmessage.MsgDoneIBDBlocks:
|
||||
return nil, true, nil
|
||||
default:
|
||||
return nil, false,
|
||||
protocolerrors.Errorf(true, "received unexpected message type. "+
|
||||
"expected: %s, got: %s", wire.CmdIBDBlock, message.Command())
|
||||
"expected: %s, got: %s", appmessage.CmdIBDBlock, message.Command())
|
||||
}
|
||||
}
|
||||
|
||||
func (flow *handleIBDFlow) processIBDBlock(msgIBDBlock *wire.MsgIBDBlock) error {
|
||||
|
||||
func (flow *handleIBDFlow) processIBDBlock(msgIBDBlock *appmessage.MsgIBDBlock) error {
|
||||
block := util.NewBlock(msgIBDBlock.MsgBlock)
|
||||
if flow.DAG().IsInDAG(block.Hash()) {
|
||||
log.Debugf("IBD block %s is already in the DAG. Skipping...", block.Hash())
|
||||
return nil
|
||||
}
|
||||
isOrphan, isDelayed, err := flow.DAG().ProcessBlock(block, blockdag.BFNone)
|
||||
if err != nil {
|
||||
return err
|
||||
if !errors.As(err, &blockdag.RuleError{}) {
|
||||
return errors.Wrapf(err, "failed to process block %s during IBD", block.Hash())
|
||||
}
|
||||
log.Infof("Rejected block %s from %s during IBD: %s", block.Hash(), flow.peer, err)
|
||||
|
||||
return protocolerrors.Wrapf(true, err, "got invalid block %s during IBD", block.Hash())
|
||||
}
|
||||
if isOrphan {
|
||||
return protocolerrors.Errorf(true, "received orphan block %s "+
|
||||
@@ -194,5 +204,9 @@ func (flow *handleIBDFlow) processIBDBlock(msgIBDBlock *wire.MsgIBDBlock) error
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = blocklogger.LogBlock(block)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
package ibd
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/logger"
|
||||
"github.com/kaspanet/kaspad/infrastructure/logger"
|
||||
"github.com/kaspanet/kaspad/util/panics"
|
||||
)
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package selectedtip
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/blockdag"
|
||||
"github.com/kaspanet/kaspad/netadapter/router"
|
||||
"github.com/kaspanet/kaspad/wire"
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
"github.com/kaspanet/kaspad/domain/blockdag"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
@@ -46,16 +46,16 @@ func (flow *handleRequestSelectedTipFlow) receiveGetSelectedTip() error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, ok := message.(*wire.MsgRequestSelectedTip)
|
||||
_, ok := message.(*appmessage.MsgRequestSelectedTip)
|
||||
if !ok {
|
||||
return errors.Errorf("received unexpected message type. "+
|
||||
"expected: %s, got: %s", wire.CmdRequestSelectedTip, message.Command())
|
||||
"expected: %s, got: %s", appmessage.CmdRequestSelectedTip, message.Command())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (flow *handleRequestSelectedTipFlow) sendSelectedTipHash() error {
|
||||
msgSelectedTip := wire.NewMsgSelectedTip(flow.DAG().SelectedTipHash())
|
||||
msgSelectedTip := appmessage.NewMsgSelectedTip(flow.DAG().SelectedTipHash())
|
||||
return flow.outgoingRoute.Enqueue(msgSelectedTip)
|
||||
}
|
||||
@@ -1,12 +1,12 @@
|
||||
package selectedtip
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/blockdag"
|
||||
"github.com/kaspanet/kaspad/netadapter/router"
|
||||
"github.com/kaspanet/kaspad/protocol/common"
|
||||
peerpkg "github.com/kaspanet/kaspad/protocol/peer"
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
"github.com/kaspanet/kaspad/app/protocol/common"
|
||||
peerpkg "github.com/kaspanet/kaspad/app/protocol/peer"
|
||||
"github.com/kaspanet/kaspad/domain/blockdag"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
||||
"github.com/kaspanet/kaspad/util/daghash"
|
||||
"github.com/kaspanet/kaspad/wire"
|
||||
)
|
||||
|
||||
// RequestSelectedTipContext is the interface for the context needed for the RequestSelectedTip flow.
|
||||
@@ -64,7 +64,7 @@ func (flow *requestSelectedTipFlow) runSelectedTipRequest() error {
|
||||
}
|
||||
|
||||
func (flow *requestSelectedTipFlow) requestSelectedTip() error {
|
||||
msgGetSelectedTip := wire.NewMsgRequestSelectedTip()
|
||||
msgGetSelectedTip := appmessage.NewMsgRequestSelectedTip()
|
||||
return flow.outgoingRoute.Enqueue(msgGetSelectedTip)
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ func (flow *requestSelectedTipFlow) receiveSelectedTip() (selectedTipHash *dagha
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
msgSelectedTip := message.(*wire.MsgSelectedTip)
|
||||
msgSelectedTip := message.(*appmessage.MsgSelectedTip)
|
||||
|
||||
return msgSelectedTip.SelectedTipHash, nil
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
package ping
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/netadapter/router"
|
||||
"github.com/kaspanet/kaspad/wire"
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
||||
)
|
||||
|
||||
// ReceivePingsContext is the interface for the context needed for the ReceivePings flow.
|
||||
@@ -31,9 +31,9 @@ func (flow *receivePingsFlow) start() error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pingMessage := message.(*wire.MsgPing)
|
||||
pingMessage := message.(*appmessage.MsgPing)
|
||||
|
||||
pongMessage := wire.NewMsgPong(pingMessage.Nonce)
|
||||
pongMessage := appmessage.NewMsgPong(pingMessage.Nonce)
|
||||
err = flow.outgoingRoute.Enqueue(pongMessage)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -1,14 +1,14 @@
|
||||
package ping
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/app/protocol/common"
|
||||
"time"
|
||||
|
||||
"github.com/kaspanet/kaspad/netadapter/router"
|
||||
"github.com/kaspanet/kaspad/protocol/common"
|
||||
peerpkg "github.com/kaspanet/kaspad/protocol/peer"
|
||||
"github.com/kaspanet/kaspad/protocol/protocolerrors"
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
peerpkg "github.com/kaspanet/kaspad/app/protocol/peer"
|
||||
"github.com/kaspanet/kaspad/app/protocol/protocolerrors"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
||||
"github.com/kaspanet/kaspad/util/random"
|
||||
"github.com/kaspanet/kaspad/wire"
|
||||
)
|
||||
|
||||
// SendPingsContext is the interface for the context needed for the SendPings flow.
|
||||
@@ -46,7 +46,7 @@ func (flow *sendPingsFlow) start() error {
|
||||
}
|
||||
flow.peer.SetPingPending(nonce)
|
||||
|
||||
pingMessage := wire.NewMsgPing(nonce)
|
||||
pingMessage := appmessage.NewMsgPing(nonce)
|
||||
err = flow.outgoingRoute.Enqueue(pingMessage)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -56,7 +56,7 @@ func (flow *sendPingsFlow) start() error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pongMessage := message.(*wire.MsgPong)
|
||||
pongMessage := message.(*appmessage.MsgPong)
|
||||
if pongMessage.Nonce != pingMessage.Nonce {
|
||||
return protocolerrors.New(true, "nonce mismatch between ping and pong")
|
||||
}
|
||||
42
app/protocol/flows/rejects/handle_rejects.go
Normal file
42
app/protocol/flows/rejects/handle_rejects.go
Normal file
@@ -0,0 +1,42 @@
|
||||
package rejects
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
"github.com/kaspanet/kaspad/app/protocol/protocolerrors"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
||||
)
|
||||
|
||||
// HandleRejectsContext is the interface for the context needed for the HandleRejects flow.
|
||||
type HandleRejectsContext interface {
|
||||
}
|
||||
|
||||
type handleRejectsFlow struct {
|
||||
HandleRejectsContext
|
||||
incomingRoute, outgoingRoute *router.Route
|
||||
}
|
||||
|
||||
// HandleRejects handles all reject messages coming through incomingRoute.
|
||||
// This function assumes that incomingRoute will only return MsgReject.
|
||||
func HandleRejects(context HandleRejectsContext, incomingRoute *router.Route, outgoingRoute *router.Route) error {
|
||||
flow := &handleRejectsFlow{
|
||||
HandleRejectsContext: context,
|
||||
incomingRoute: incomingRoute,
|
||||
outgoingRoute: outgoingRoute,
|
||||
}
|
||||
return flow.start()
|
||||
}
|
||||
|
||||
func (flow *handleRejectsFlow) start() error {
|
||||
message, err := flow.incomingRoute.Dequeue()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rejectMessage := message.(*appmessage.MsgReject)
|
||||
|
||||
const maxReasonLength = 255
|
||||
if len(rejectMessage.Reason) > maxReasonLength {
|
||||
return protocolerrors.Errorf(false, "got reject message longer than %d", maxReasonLength)
|
||||
}
|
||||
|
||||
return protocolerrors.Errorf(false, "got reject message: `%s`", rejectMessage.Reason)
|
||||
}
|
||||
@@ -1,15 +1,15 @@
|
||||
package relaytransactions
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/blockdag"
|
||||
"github.com/kaspanet/kaspad/mempool"
|
||||
"github.com/kaspanet/kaspad/netadapter"
|
||||
"github.com/kaspanet/kaspad/netadapter/router"
|
||||
"github.com/kaspanet/kaspad/protocol/common"
|
||||
"github.com/kaspanet/kaspad/protocol/protocolerrors"
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
"github.com/kaspanet/kaspad/app/protocol/common"
|
||||
"github.com/kaspanet/kaspad/app/protocol/protocolerrors"
|
||||
"github.com/kaspanet/kaspad/domain/blockdag"
|
||||
"github.com/kaspanet/kaspad/domain/mempool"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
||||
"github.com/kaspanet/kaspad/util"
|
||||
"github.com/kaspanet/kaspad/util/daghash"
|
||||
"github.com/kaspanet/kaspad/wire"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
@@ -20,23 +20,23 @@ type TransactionsRelayContext interface {
|
||||
DAG() *blockdag.BlockDAG
|
||||
SharedRequestedTransactions() *SharedRequestedTransactions
|
||||
TxPool() *mempool.TxPool
|
||||
Broadcast(message wire.Message) error
|
||||
Broadcast(message appmessage.Message) error
|
||||
}
|
||||
|
||||
type handleRelayedTransactionsFlow struct {
|
||||
TransactionsRelayContext
|
||||
incomingRoute, outgoingRoute *router.Route
|
||||
invsQueue []*wire.MsgInvTransaction
|
||||
invsQueue []*appmessage.MsgInvTransaction
|
||||
}
|
||||
|
||||
// HandleRelayedTransactions listens to wire.MsgInvTransaction messages, requests their corresponding transactions if they
|
||||
// HandleRelayedTransactions listens to appmessage.MsgInvTransaction messages, requests their corresponding transactions if they
|
||||
// are missing, adds them to the mempool and propagates them to the rest of the network.
|
||||
func HandleRelayedTransactions(context TransactionsRelayContext, incomingRoute *router.Route, outgoingRoute *router.Route) error {
|
||||
flow := &handleRelayedTransactionsFlow{
|
||||
TransactionsRelayContext: context,
|
||||
incomingRoute: incomingRoute,
|
||||
outgoingRoute: outgoingRoute,
|
||||
invsQueue: make([]*wire.MsgInvTransaction, 0),
|
||||
invsQueue: make([]*appmessage.MsgInvTransaction, 0),
|
||||
}
|
||||
return flow.start()
|
||||
}
|
||||
@@ -61,7 +61,7 @@ func (flow *handleRelayedTransactionsFlow) start() error {
|
||||
}
|
||||
|
||||
func (flow *handleRelayedTransactionsFlow) requestInvTransactions(
|
||||
inv *wire.MsgInvTransaction) (requestedIDs []*daghash.TxID, err error) {
|
||||
inv *appmessage.MsgInvTransaction) (requestedIDs []*daghash.TxID, err error) {
|
||||
|
||||
idsToRequest := make([]*daghash.TxID, 0, len(inv.TxIDs))
|
||||
for _, txID := range inv.TxIDs {
|
||||
@@ -79,7 +79,7 @@ func (flow *handleRelayedTransactionsFlow) requestInvTransactions(
|
||||
return idsToRequest, nil
|
||||
}
|
||||
|
||||
msgGetTransactions := wire.NewMsgRequestTransactions(idsToRequest)
|
||||
msgGetTransactions := appmessage.NewMsgRequestTransactions(idsToRequest)
|
||||
err = flow.outgoingRoute.Enqueue(msgGetTransactions)
|
||||
if err != nil {
|
||||
flow.SharedRequestedTransactions().removeMany(idsToRequest)
|
||||
@@ -103,7 +103,7 @@ func (flow *handleRelayedTransactionsFlow) isKnownTransaction(txID *daghash.TxID
|
||||
// checked because the vast majority of transactions consist of
|
||||
// two outputs where one is some form of "pay-to-somebody-else"
|
||||
// and the other is a change output.
|
||||
prevOut := wire.Outpoint{TxID: *txID}
|
||||
prevOut := appmessage.Outpoint{TxID: *txID}
|
||||
for i := uint32(0); i < 2; i++ {
|
||||
prevOut.Index = i
|
||||
_, ok := flow.DAG().GetUTXOEntry(prevOut)
|
||||
@@ -114,9 +114,9 @@ func (flow *handleRelayedTransactionsFlow) isKnownTransaction(txID *daghash.TxID
|
||||
return false
|
||||
}
|
||||
|
||||
func (flow *handleRelayedTransactionsFlow) readInv() (*wire.MsgInvTransaction, error) {
|
||||
func (flow *handleRelayedTransactionsFlow) readInv() (*appmessage.MsgInvTransaction, error) {
|
||||
if len(flow.invsQueue) > 0 {
|
||||
var inv *wire.MsgInvTransaction
|
||||
var inv *appmessage.MsgInvTransaction
|
||||
inv, flow.invsQueue = flow.invsQueue[0], flow.invsQueue[1:]
|
||||
return inv, nil
|
||||
}
|
||||
@@ -126,7 +126,7 @@ func (flow *handleRelayedTransactionsFlow) readInv() (*wire.MsgInvTransaction, e
|
||||
return nil, err
|
||||
}
|
||||
|
||||
inv, ok := msg.(*wire.MsgInvTransaction)
|
||||
inv, ok := msg.(*appmessage.MsgInvTransaction)
|
||||
if !ok {
|
||||
return nil, protocolerrors.Errorf(true, "unexpected %s message in the block relay flow while "+
|
||||
"expecting an inv message", msg.Command())
|
||||
@@ -135,13 +135,11 @@ func (flow *handleRelayedTransactionsFlow) readInv() (*wire.MsgInvTransaction, e
|
||||
}
|
||||
|
||||
func (flow *handleRelayedTransactionsFlow) broadcastAcceptedTransactions(acceptedTxs []*mempool.TxDesc) error {
|
||||
// TODO(libp2p) Add mechanism to avoid sending to other peers invs that are known to them (e.g. mruinvmap)
|
||||
// TODO(libp2p) Consider broadcasting in bulks
|
||||
idsToBroadcast := make([]*daghash.TxID, len(acceptedTxs))
|
||||
for i, tx := range acceptedTxs {
|
||||
idsToBroadcast[i] = tx.Tx.ID()
|
||||
}
|
||||
inv := wire.NewMsgInvTransaction(idsToBroadcast)
|
||||
inv := appmessage.NewMsgInvTransaction(idsToBroadcast)
|
||||
return flow.Broadcast(inv)
|
||||
}
|
||||
|
||||
@@ -150,7 +148,7 @@ func (flow *handleRelayedTransactionsFlow) broadcastAcceptedTransactions(accepte
|
||||
//
|
||||
// and populates invsQueue with any inv messages that meanwhile arrive.
|
||||
func (flow *handleRelayedTransactionsFlow) readMsgTxOrNotFound() (
|
||||
msgTx *wire.MsgTx, msgNotFound *wire.MsgTransactionNotFound, err error) {
|
||||
msgTx *appmessage.MsgTx, msgNotFound *appmessage.MsgTransactionNotFound, err error) {
|
||||
|
||||
for {
|
||||
message, err := flow.incomingRoute.DequeueWithTimeout(common.DefaultTimeout)
|
||||
@@ -159,11 +157,11 @@ func (flow *handleRelayedTransactionsFlow) readMsgTxOrNotFound() (
|
||||
}
|
||||
|
||||
switch message := message.(type) {
|
||||
case *wire.MsgInvTransaction:
|
||||
case *appmessage.MsgInvTransaction:
|
||||
flow.invsQueue = append(flow.invsQueue, message)
|
||||
case *wire.MsgTx:
|
||||
case *appmessage.MsgTx:
|
||||
return message, nil, nil
|
||||
case *wire.MsgTransactionNotFound:
|
||||
case *appmessage.MsgTransactionNotFound:
|
||||
return nil, message, nil
|
||||
default:
|
||||
return nil, nil, errors.Errorf("unexpected message %s", message.Command())
|
||||
@@ -194,7 +192,7 @@ func (flow *handleRelayedTransactionsFlow) receiveTransactions(requestedTransact
|
||||
expectedID, tx.ID())
|
||||
}
|
||||
|
||||
acceptedTxs, err := flow.TxPool().ProcessTransaction(tx, true, 0) // TODO(libp2p) Use the peer ID for the mempool tag
|
||||
acceptedTxs, err := flow.TxPool().ProcessTransaction(tx, true)
|
||||
if err != nil {
|
||||
ruleErr := &mempool.RuleError{}
|
||||
if !errors.As(err, ruleErr) {
|
||||
@@ -220,7 +218,6 @@ func (flow *handleRelayedTransactionsFlow) receiveTransactions(requestedTransact
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// TODO(libp2p) Notify transactionsAcceptedToMempool to RPC
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
package relaytransactions
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/netadapter/router"
|
||||
"github.com/kaspanet/kaspad/wire"
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
||||
)
|
||||
|
||||
type handleRequestedTransactionsFlow struct {
|
||||
@@ -10,7 +10,7 @@ type handleRequestedTransactionsFlow struct {
|
||||
incomingRoute, outgoingRoute *router.Route
|
||||
}
|
||||
|
||||
// HandleRequestedTransactions listens to wire.MsgRequestTransactions messages, responding with the requested
|
||||
// HandleRequestedTransactions listens to appmessage.MsgRequestTransactions messages, responding with the requested
|
||||
// transactions if those are in the mempool.
|
||||
// Missing transactions would be ignored
|
||||
func HandleRequestedTransactions(context TransactionsRelayContext, incomingRoute *router.Route, outgoingRoute *router.Route) error {
|
||||
@@ -33,7 +33,7 @@ func (flow *handleRequestedTransactionsFlow) start() error {
|
||||
tx, ok := flow.TxPool().FetchTransaction(transactionID)
|
||||
|
||||
if !ok {
|
||||
msgTransactionNotFound := wire.NewMsgTransactionNotFound(transactionID)
|
||||
msgTransactionNotFound := appmessage.NewMsgTransactionNotFound(transactionID)
|
||||
err := flow.outgoingRoute.Enqueue(msgTransactionNotFound)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -49,11 +49,11 @@ func (flow *handleRequestedTransactionsFlow) start() error {
|
||||
}
|
||||
}
|
||||
|
||||
func (flow *handleRequestedTransactionsFlow) readRequestTransactions() (*wire.MsgRequestTransactions, error) {
|
||||
func (flow *handleRequestedTransactionsFlow) readRequestTransactions() (*appmessage.MsgRequestTransactions, error) {
|
||||
msg, err := flow.incomingRoute.Dequeue()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return msg.(*wire.MsgRequestTransactions), nil
|
||||
return msg.(*appmessage.MsgRequestTransactions), nil
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
package protocol
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/logger"
|
||||
"github.com/kaspanet/kaspad/infrastructure/logger"
|
||||
"github.com/kaspanet/kaspad/util/panics"
|
||||
)
|
||||
|
||||
@@ -3,17 +3,15 @@ package protocol
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/kaspanet/kaspad/addressmanager"
|
||||
"github.com/kaspanet/kaspad/blockdag"
|
||||
"github.com/kaspanet/kaspad/config"
|
||||
"github.com/kaspanet/kaspad/connmanager"
|
||||
"github.com/kaspanet/kaspad/mempool"
|
||||
"github.com/kaspanet/kaspad/netadapter"
|
||||
"github.com/kaspanet/kaspad/protocol/flowcontext"
|
||||
peerpkg "github.com/kaspanet/kaspad/protocol/peer"
|
||||
"github.com/kaspanet/kaspad/protocol/protocolerrors"
|
||||
"github.com/kaspanet/kaspad/app/protocol/flowcontext"
|
||||
peerpkg "github.com/kaspanet/kaspad/app/protocol/peer"
|
||||
"github.com/kaspanet/kaspad/domain/blockdag"
|
||||
"github.com/kaspanet/kaspad/domain/mempool"
|
||||
"github.com/kaspanet/kaspad/infrastructure/config"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/addressmanager"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/connmanager"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter"
|
||||
"github.com/kaspanet/kaspad/util"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// Manager manages the p2p protocol
|
||||
@@ -56,30 +54,12 @@ func (m *Manager) IBDPeer() *peerpkg.Peer {
|
||||
|
||||
// AddTransaction adds transaction to the mempool and propagates it.
|
||||
func (m *Manager) AddTransaction(tx *util.Tx) error {
|
||||
err := m.context.AddTransaction(tx)
|
||||
if err != nil {
|
||||
if protocolErr := &(protocolerrors.ProtocolError{}); errors.As(err, &protocolErr) {
|
||||
return err
|
||||
}
|
||||
|
||||
// TODO(libp2p): Remove panic once RPC is integrated into protocol architecture
|
||||
panic(err)
|
||||
}
|
||||
return nil
|
||||
return m.context.AddTransaction(tx)
|
||||
}
|
||||
|
||||
// AddBlock adds the given block to the DAG and propagates it.
|
||||
func (m *Manager) AddBlock(block *util.Block, flags blockdag.BehaviorFlags) error {
|
||||
err := m.context.AddBlock(block, flags)
|
||||
if err != nil {
|
||||
if protocolErr := &(protocolerrors.ProtocolError{}); errors.As(err, &protocolErr) {
|
||||
return err
|
||||
}
|
||||
|
||||
// TODO(libp2p): Remove panic once RPC is integrated into protocol architecture
|
||||
panic(err)
|
||||
}
|
||||
return nil
|
||||
return m.context.AddBlock(block, flags)
|
||||
}
|
||||
|
||||
func (m *Manager) runFlows(flows []*flow, peer *peerpkg.Peer, errChan <-chan error) error {
|
||||
@@ -1,7 +1,7 @@
|
||||
package peer
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/logger"
|
||||
"github.com/kaspanet/kaspad/infrastructure/logger"
|
||||
"github.com/kaspanet/kaspad/util/panics"
|
||||
)
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
package peer
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/netadapter"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/kaspanet/kaspad/netadapter/id"
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/id"
|
||||
"github.com/kaspanet/kaspad/util/daghash"
|
||||
mathUtil "github.com/kaspanet/kaspad/util/math"
|
||||
"github.com/kaspanet/kaspad/util/mstime"
|
||||
"github.com/kaspanet/kaspad/util/subnetworkid"
|
||||
"github.com/kaspanet/kaspad/wire"
|
||||
)
|
||||
|
||||
// Peer holds data about a peer.
|
||||
@@ -22,7 +22,7 @@ type Peer struct {
|
||||
selectedTipHash *daghash.Hash
|
||||
|
||||
userAgent string
|
||||
services wire.ServiceFlag
|
||||
services appmessage.ServiceFlag
|
||||
advertisedProtocolVerion uint32 // protocol version advertised by remote
|
||||
protocolVersion uint32 // negotiated protocol version
|
||||
disableRelayTx bool
|
||||
@@ -109,7 +109,7 @@ func (p *Peer) IsOutbound() bool {
|
||||
}
|
||||
|
||||
// UpdateFieldsFromMsgVersion updates the peer with the data from the version message.
|
||||
func (p *Peer) UpdateFieldsFromMsgVersion(msg *wire.MsgVersion) {
|
||||
func (p *Peer) UpdateFieldsFromMsgVersion(msg *appmessage.MsgVersion) {
|
||||
// Negotiate the protocol version.
|
||||
p.advertisedProtocolVerion = msg.ProtocolVersion
|
||||
p.protocolVersion = mathUtil.MinUint32(p.protocolVersion, p.advertisedProtocolVerion)
|
||||
@@ -1,21 +1,22 @@
|
||||
package protocol
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/app/protocol/flows/rejects"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/kaspanet/kaspad/addressmanager"
|
||||
"github.com/kaspanet/kaspad/netadapter"
|
||||
routerpkg "github.com/kaspanet/kaspad/netadapter/router"
|
||||
"github.com/kaspanet/kaspad/protocol/flows/addressexchange"
|
||||
"github.com/kaspanet/kaspad/protocol/flows/blockrelay"
|
||||
"github.com/kaspanet/kaspad/protocol/flows/handshake"
|
||||
"github.com/kaspanet/kaspad/protocol/flows/ibd"
|
||||
"github.com/kaspanet/kaspad/protocol/flows/ibd/selectedtip"
|
||||
"github.com/kaspanet/kaspad/protocol/flows/ping"
|
||||
"github.com/kaspanet/kaspad/protocol/flows/relaytransactions"
|
||||
peerpkg "github.com/kaspanet/kaspad/protocol/peer"
|
||||
"github.com/kaspanet/kaspad/protocol/protocolerrors"
|
||||
"github.com/kaspanet/kaspad/wire"
|
||||
"github.com/kaspanet/kaspad/app/appmessage"
|
||||
"github.com/kaspanet/kaspad/app/protocol/flows/addressexchange"
|
||||
"github.com/kaspanet/kaspad/app/protocol/flows/blockrelay"
|
||||
"github.com/kaspanet/kaspad/app/protocol/flows/handshake"
|
||||
"github.com/kaspanet/kaspad/app/protocol/flows/ibd"
|
||||
"github.com/kaspanet/kaspad/app/protocol/flows/ibd/selectedtip"
|
||||
"github.com/kaspanet/kaspad/app/protocol/flows/ping"
|
||||
"github.com/kaspanet/kaspad/app/protocol/flows/relaytransactions"
|
||||
peerpkg "github.com/kaspanet/kaspad/app/protocol/peer"
|
||||
"github.com/kaspanet/kaspad/app/protocol/protocolerrors"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/addressmanager"
|
||||
"github.com/kaspanet/kaspad/infrastructure/network/netadapter"
|
||||
routerpkg "github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
@@ -49,37 +50,50 @@ func (m *Manager) routerInitializer(router *routerpkg.Router, netConnection *net
|
||||
return
|
||||
}
|
||||
|
||||
netConnection.SetOnInvalidMessageHandler(func(err error) {
|
||||
if atomic.AddUint32(&isStopping, 1) == 1 {
|
||||
errChan <- protocolerrors.Wrap(true, err, "received bad message")
|
||||
spawn("Manager.routerInitializer-netConnection.DequeueInvalidMessage", func() {
|
||||
for {
|
||||
isOpen, err := netConnection.DequeueInvalidMessage()
|
||||
if !isOpen {
|
||||
return
|
||||
}
|
||||
if atomic.AddUint32(&isStopping, 1) == 1 {
|
||||
errChan <- protocolerrors.Wrap(true, err, "received bad message")
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
peer, err := handshake.HandleHandshake(m.context, netConnection, receiveVersionRoute,
|
||||
sendVersionRoute, router.OutgoingRoute())
|
||||
if err != nil {
|
||||
m.handleError(err, netConnection)
|
||||
m.handleError(err, netConnection, router.OutgoingRoute())
|
||||
return
|
||||
}
|
||||
defer m.context.RemoveFromPeers(peer)
|
||||
|
||||
removeHandshakeRoutes(router)
|
||||
|
||||
err = m.runFlows(flows, peer, errChan)
|
||||
if err != nil {
|
||||
m.handleError(err, netConnection)
|
||||
m.handleError(err, netConnection, router.OutgoingRoute())
|
||||
return
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func (m *Manager) handleError(err error, netConnection *netadapter.NetConnection) {
|
||||
func (m *Manager) handleError(err error, netConnection *netadapter.NetConnection, outgoingRoute *routerpkg.Route) {
|
||||
if protocolErr := &(protocolerrors.ProtocolError{}); errors.As(err, &protocolErr) {
|
||||
if !m.context.Config().DisableBanning && protocolErr.ShouldBan {
|
||||
log.Warnf("Banning %s (reason: %s)", netConnection, protocolErr.Cause)
|
||||
|
||||
err := m.context.ConnectionManager().Ban(netConnection)
|
||||
if err != nil && !errors.Is(err, addressmanager.ErrAddressNotFound) {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = outgoingRoute.Enqueue(appmessage.NewMsgReject(protocolErr.Error()))
|
||||
if err != nil && !errors.Is(err, routerpkg.ErrRouteClosed) {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
netConnection.Disconnect()
|
||||
return
|
||||
@@ -101,6 +115,7 @@ func (m *Manager) registerFlows(router *routerpkg.Router, errChan chan error, is
|
||||
flows = append(flows, m.registerPingFlows(router, isStopping, errChan)...)
|
||||
flows = append(flows, m.registerIBDFlows(router, isStopping, errChan)...)
|
||||
flows = append(flows, m.registerTransactionRelayFlow(router, isStopping, errChan)...)
|
||||
flows = append(flows, m.registerRejectsFlow(router, isStopping, errChan)...)
|
||||
|
||||
return flows
|
||||
}
|
||||
@@ -109,13 +124,13 @@ func (m *Manager) registerAddressFlows(router *routerpkg.Router, isStopping *uin
|
||||
outgoingRoute := router.OutgoingRoute()
|
||||
|
||||
return []*flow{
|
||||
m.registerOneTimeFlow("SendAddresses", router, []wire.MessageCommand{wire.CmdRequestAddresses}, isStopping, errChan,
|
||||
m.registerOneTimeFlow("SendAddresses", router, []appmessage.MessageCommand{appmessage.CmdRequestAddresses}, isStopping, errChan,
|
||||
func(incomingRoute *routerpkg.Route, peer *peerpkg.Peer) error {
|
||||
return addressexchange.SendAddresses(m.context, incomingRoute, outgoingRoute)
|
||||
},
|
||||
),
|
||||
|
||||
m.registerOneTimeFlow("ReceiveAddresses", router, []wire.MessageCommand{wire.CmdAddresses}, isStopping, errChan,
|
||||
m.registerOneTimeFlow("ReceiveAddresses", router, []appmessage.MessageCommand{appmessage.CmdAddresses}, isStopping, errChan,
|
||||
func(incomingRoute *routerpkg.Route, peer *peerpkg.Peer) error {
|
||||
return addressexchange.ReceiveAddresses(m.context, incomingRoute, outgoingRoute, peer)
|
||||
},
|
||||
@@ -127,14 +142,14 @@ func (m *Manager) registerBlockRelayFlows(router *routerpkg.Router, isStopping *
|
||||
outgoingRoute := router.OutgoingRoute()
|
||||
|
||||
return []*flow{
|
||||
m.registerFlow("HandleRelayInvs", router, []wire.MessageCommand{wire.CmdInvRelayBlock, wire.CmdBlock}, isStopping, errChan,
|
||||
m.registerFlow("HandleRelayInvs", router, []appmessage.MessageCommand{appmessage.CmdInvRelayBlock, appmessage.CmdBlock}, isStopping, errChan,
|
||||
func(incomingRoute *routerpkg.Route, peer *peerpkg.Peer) error {
|
||||
return blockrelay.HandleRelayInvs(m.context, incomingRoute,
|
||||
outgoingRoute, peer)
|
||||
},
|
||||
),
|
||||
|
||||
m.registerFlow("HandleRelayBlockRequests", router, []wire.MessageCommand{wire.CmdRequestRelayBlocks}, isStopping, errChan,
|
||||
m.registerFlow("HandleRelayBlockRequests", router, []appmessage.MessageCommand{appmessage.CmdRequestRelayBlocks}, isStopping, errChan,
|
||||
func(incomingRoute *routerpkg.Route, peer *peerpkg.Peer) error {
|
||||
return blockrelay.HandleRelayBlockRequests(m.context, incomingRoute, outgoingRoute, peer)
|
||||
},
|
||||
@@ -146,13 +161,13 @@ func (m *Manager) registerPingFlows(router *routerpkg.Router, isStopping *uint32
|
||||
outgoingRoute := router.OutgoingRoute()
|
||||
|
||||
return []*flow{
|
||||
m.registerFlow("ReceivePings", router, []wire.MessageCommand{wire.CmdPing}, isStopping, errChan,
|
||||
m.registerFlow("ReceivePings", router, []appmessage.MessageCommand{appmessage.CmdPing}, isStopping, errChan,
|
||||
func(incomingRoute *routerpkg.Route, peer *peerpkg.Peer) error {
|
||||
return ping.ReceivePings(m.context, incomingRoute, outgoingRoute)
|
||||
},
|
||||
),
|
||||
|
||||
m.registerFlow("SendPings", router, []wire.MessageCommand{wire.CmdPong}, isStopping, errChan,
|
||||
m.registerFlow("SendPings", router, []appmessage.MessageCommand{appmessage.CmdPong}, isStopping, errChan,
|
||||
func(incomingRoute *routerpkg.Route, peer *peerpkg.Peer) error {
|
||||
return ping.SendPings(m.context, incomingRoute, outgoingRoute, peer)
|
||||
},
|
||||
@@ -164,32 +179,32 @@ func (m *Manager) registerIBDFlows(router *routerpkg.Router, isStopping *uint32,
|
||||
outgoingRoute := router.OutgoingRoute()
|
||||
|
||||
return []*flow{
|
||||
m.registerFlow("HandleIBD", router, []wire.MessageCommand{wire.CmdBlockLocator, wire.CmdIBDBlock,
|
||||
wire.CmdDoneIBDBlocks}, isStopping, errChan,
|
||||
m.registerFlow("HandleIBD", router, []appmessage.MessageCommand{appmessage.CmdBlockLocator, appmessage.CmdIBDBlock,
|
||||
appmessage.CmdDoneIBDBlocks}, isStopping, errChan,
|
||||
func(incomingRoute *routerpkg.Route, peer *peerpkg.Peer) error {
|
||||
return ibd.HandleIBD(m.context, incomingRoute, outgoingRoute, peer)
|
||||
},
|
||||
),
|
||||
|
||||
m.registerFlow("RequestSelectedTip", router, []wire.MessageCommand{wire.CmdSelectedTip}, isStopping, errChan,
|
||||
m.registerFlow("RequestSelectedTip", router, []appmessage.MessageCommand{appmessage.CmdSelectedTip}, isStopping, errChan,
|
||||
func(incomingRoute *routerpkg.Route, peer *peerpkg.Peer) error {
|
||||
return selectedtip.RequestSelectedTip(m.context, incomingRoute, outgoingRoute, peer)
|
||||
},
|
||||
),
|
||||
|
||||
m.registerFlow("HandleRequestSelectedTip", router, []wire.MessageCommand{wire.CmdRequestSelectedTip}, isStopping, errChan,
|
||||
m.registerFlow("HandleRequestSelectedTip", router, []appmessage.MessageCommand{appmessage.CmdRequestSelectedTip}, isStopping, errChan,
|
||||
func(incomingRoute *routerpkg.Route, peer *peerpkg.Peer) error {
|
||||
return selectedtip.HandleRequestSelectedTip(m.context, incomingRoute, outgoingRoute)
|
||||
},
|
||||
),
|
||||
|
||||
m.registerFlow("HandleRequestBlockLocator", router, []wire.MessageCommand{wire.CmdRequestBlockLocator}, isStopping, errChan,
|
||||
m.registerFlow("HandleRequestBlockLocator", router, []appmessage.MessageCommand{appmessage.CmdRequestBlockLocator}, isStopping, errChan,
|
||||
func(incomingRoute *routerpkg.Route, peer *peerpkg.Peer) error {
|
||||
return ibd.HandleRequestBlockLocator(m.context, incomingRoute, outgoingRoute)
|
||||
},
|
||||
),
|
||||
|
||||
m.registerFlow("HandleRequestIBDBlocks", router, []wire.MessageCommand{wire.CmdRequestIBDBlocks, wire.CmdRequestNextIBDBlocks}, isStopping, errChan,
|
||||
m.registerFlow("HandleRequestIBDBlocks", router, []appmessage.MessageCommand{appmessage.CmdRequestIBDBlocks, appmessage.CmdRequestNextIBDBlocks}, isStopping, errChan,
|
||||
func(incomingRoute *routerpkg.Route, peer *peerpkg.Peer) error {
|
||||
return ibd.HandleRequestIBDBlocks(m.context, incomingRoute, outgoingRoute)
|
||||
},
|
||||
@@ -202,13 +217,13 @@ func (m *Manager) registerTransactionRelayFlow(router *routerpkg.Router, isStopp
|
||||
|
||||
return []*flow{
|
||||
m.registerFlow("HandleRelayedTransactions", router,
|
||||
[]wire.MessageCommand{wire.CmdInvTransaction, wire.CmdTx, wire.CmdTransactionNotFound}, isStopping, errChan,
|
||||
[]appmessage.MessageCommand{appmessage.CmdInvTransaction, appmessage.CmdTx, appmessage.CmdTransactionNotFound}, isStopping, errChan,
|
||||
func(incomingRoute *routerpkg.Route, peer *peerpkg.Peer) error {
|
||||
return relaytransactions.HandleRelayedTransactions(m.context, incomingRoute, outgoingRoute)
|
||||
},
|
||||
),
|
||||
m.registerFlow("HandleRequestTransactions", router,
|
||||
[]wire.MessageCommand{wire.CmdRequestTransactions}, isStopping, errChan,
|
||||
[]appmessage.MessageCommand{appmessage.CmdRequestTransactions}, isStopping, errChan,
|
||||
func(incomingRoute *routerpkg.Route, peer *peerpkg.Peer) error {
|
||||
return relaytransactions.HandleRequestedTransactions(m.context, incomingRoute, outgoingRoute)
|
||||
},
|
||||
@@ -216,7 +231,20 @@ func (m *Manager) registerTransactionRelayFlow(router *routerpkg.Router, isStopp
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Manager) registerFlow(name string, router *routerpkg.Router, messageTypes []wire.MessageCommand, isStopping *uint32,
|
||||
func (m *Manager) registerRejectsFlow(router *routerpkg.Router, isStopping *uint32, errChan chan error) []*flow {
|
||||
outgoingRoute := router.OutgoingRoute()
|
||||
|
||||
return []*flow{
|
||||
m.registerFlow("HandleRejects", router,
|
||||
[]appmessage.MessageCommand{appmessage.CmdReject}, isStopping, errChan,
|
||||
func(incomingRoute *routerpkg.Route, peer *peerpkg.Peer) error {
|
||||
return rejects.HandleRejects(m.context, incomingRoute, outgoingRoute)
|
||||
},
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Manager) registerFlow(name string, router *routerpkg.Router, messageTypes []appmessage.MessageCommand, isStopping *uint32,
|
||||
errChan chan error, initializeFunc flowInitializeFunc) *flow {
|
||||
|
||||
route, err := router.AddIncomingRoute(messageTypes)
|
||||
@@ -236,7 +264,7 @@ func (m *Manager) registerFlow(name string, router *routerpkg.Router, messageTyp
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Manager) registerOneTimeFlow(name string, router *routerpkg.Router, messageTypes []wire.MessageCommand,
|
||||
func (m *Manager) registerOneTimeFlow(name string, router *routerpkg.Router, messageTypes []appmessage.MessageCommand,
|
||||
isStopping *uint32, stopChan chan error, initializeFunc flowInitializeFunc) *flow {
|
||||
|
||||
route, err := router.AddIncomingRoute(messageTypes)
|
||||
@@ -265,12 +293,12 @@ func (m *Manager) registerOneTimeFlow(name string, router *routerpkg.Router, mes
|
||||
|
||||
func registerHandshakeRoutes(router *routerpkg.Router) (
|
||||
receiveVersionRoute *routerpkg.Route, sendVersionRoute *routerpkg.Route) {
|
||||
receiveVersionRoute, err := router.AddIncomingRoute([]wire.MessageCommand{wire.CmdVersion})
|
||||
receiveVersionRoute, err := router.AddIncomingRoute([]appmessage.MessageCommand{appmessage.CmdVersion})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
sendVersionRoute, err = router.AddIncomingRoute([]wire.MessageCommand{wire.CmdVerAck})
|
||||
sendVersionRoute, err = router.AddIncomingRoute([]appmessage.MessageCommand{appmessage.CmdVerAck})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -279,7 +307,7 @@ func registerHandshakeRoutes(router *routerpkg.Router) (
|
||||
}
|
||||
|
||||
func removeHandshakeRoutes(router *routerpkg.Router) {
|
||||
err := router.RemoveRoute([]wire.MessageCommand{wire.CmdVersion, wire.CmdVerAck})
|
||||
err := router.RemoveRoute([]appmessage.MessageCommand{appmessage.CmdVersion, appmessage.CmdVerAck})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -18,8 +18,7 @@ func (e *ProtocolError) Unwrap() error {
|
||||
}
|
||||
|
||||
// Errorf formats according to a format specifier and returns the string
|
||||
// as a value that satisfies error.
|
||||
// Errorf also records the stack trace at the point it was called.
|
||||
// as a ProtocolError.
|
||||
func Errorf(shouldBan bool, format string, args ...interface{}) error {
|
||||
return &ProtocolError{
|
||||
ShouldBan: shouldBan,
|
||||
@@ -27,7 +26,7 @@ func Errorf(shouldBan bool, format string, args ...interface{}) error {
|
||||
}
|
||||
}
|
||||
|
||||
// New returns an error with the supplied message.
|
||||
// New returns a ProtocolError with the supplied message.
|
||||
// New also records the stack trace at the point it was called.
|
||||
func New(shouldBan bool, message string) error {
|
||||
return &ProtocolError{
|
||||
@@ -36,8 +35,7 @@ func New(shouldBan bool, message string) error {
|
||||
}
|
||||
}
|
||||
|
||||
// Wrap returns an error annotating err with a stack trace
|
||||
// at the point Wrap is called, and the supplied message.
|
||||
// Wrap wraps the given error and returns it as a ProtocolError.
|
||||
func Wrap(shouldBan bool, err error, message string) error {
|
||||
return &ProtocolError{
|
||||
ShouldBan: shouldBan,
|
||||
@@ -45,8 +43,7 @@ func Wrap(shouldBan bool, err error, message string) error {
|
||||
}
|
||||
}
|
||||
|
||||
// Wrapf returns an error annotating err with a stack trace
|
||||
// at the point Wrapf is called, and the format specifier.
|
||||
// Wrapf wraps the given error with the given format and returns it as a ProtocolError.
|
||||
func Wrapf(shouldBan bool, err error, format string, args ...interface{}) error {
|
||||
return &ProtocolError{
|
||||
ShouldBan: shouldBan,
|
||||
@@ -1,154 +0,0 @@
|
||||
// Copyright (c) 2013-2017 The btcsuite developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package blockdag
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/kaspanet/kaspad/dbaccess"
|
||||
"github.com/kaspanet/kaspad/util"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func (dag *BlockDAG) addNodeToIndexWithInvalidAncestor(block *util.Block) error {
|
||||
blockHeader := &block.MsgBlock().Header
|
||||
newNode, _ := dag.newBlockNode(blockHeader, newBlockSet())
|
||||
newNode.status = statusInvalidAncestor
|
||||
dag.index.AddNode(newNode)
|
||||
|
||||
dbTx, err := dag.databaseContext.NewTx()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer dbTx.RollbackUnlessClosed()
|
||||
err = dag.index.flushToDB(dbTx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return dbTx.Commit()
|
||||
}
|
||||
|
||||
// maybeAcceptBlock potentially accepts a block into the block DAG. It
|
||||
// performs several validation checks which depend on its position within
|
||||
// the block DAG before adding it. The block is expected to have already
|
||||
// gone through ProcessBlock before calling this function with it.
|
||||
//
|
||||
// The flags are also passed to checkBlockContext and connectToDAG. See
|
||||
// their documentation for how the flags modify their behavior.
|
||||
//
|
||||
// This function MUST be called with the dagLock held (for writes).
|
||||
func (dag *BlockDAG) maybeAcceptBlock(block *util.Block, flags BehaviorFlags) error {
|
||||
parents, err := lookupParentNodes(block, dag)
|
||||
if err != nil {
|
||||
var ruleErr RuleError
|
||||
if ok := errors.As(err, &ruleErr); ok && ruleErr.ErrorCode == ErrInvalidAncestorBlock {
|
||||
err := dag.addNodeToIndexWithInvalidAncestor(block)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// The block must pass all of the validation rules which depend on the
|
||||
// position of the block within the block DAG.
|
||||
err = dag.checkBlockContext(block, parents, flags)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Create a new block node for the block and add it to the node index.
|
||||
newNode, selectedParentAnticone := dag.newBlockNode(&block.MsgBlock().Header, parents)
|
||||
newNode.status = statusDataStored
|
||||
dag.index.AddNode(newNode)
|
||||
|
||||
// Insert the block into the database if it's not already there. Even
|
||||
// though it is possible the block will ultimately fail to connect, it
|
||||
// has already passed all proof-of-work and validity tests which means
|
||||
// it would be prohibitively expensive for an attacker to fill up the
|
||||
// disk with a bunch of blocks that fail to connect. This is necessary
|
||||
// since it allows block download to be decoupled from the much more
|
||||
// expensive connection logic. It also has some other nice properties
|
||||
// such as making blocks that never become part of the DAG or
|
||||
// blocks that fail to connect available for further analysis.
|
||||
dbTx, err := dag.databaseContext.NewTx()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer dbTx.RollbackUnlessClosed()
|
||||
blockExists, err := dbaccess.HasBlock(dbTx, block.Hash())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !blockExists {
|
||||
err := storeBlock(dbTx, block)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
err = dag.index.flushToDB(dbTx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = dbTx.Commit()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Make sure that all the block's transactions are finalized
|
||||
fastAdd := flags&BFFastAdd == BFFastAdd
|
||||
bluestParent := parents.bluest()
|
||||
if !fastAdd {
|
||||
if err := dag.validateAllTxsFinalized(block, newNode, bluestParent); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Connect the passed block to the DAG. This also handles validation of the
|
||||
// transaction scripts.
|
||||
chainUpdates, err := dag.addBlock(newNode, block, selectedParentAnticone, flags)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Notify the caller that the new block was accepted into the block
|
||||
// DAG. The caller would typically want to react by relaying the
|
||||
// inventory to other peers.
|
||||
dag.dagLock.Unlock()
|
||||
dag.sendNotification(NTBlockAdded, &BlockAddedNotificationData{
|
||||
Block: block,
|
||||
WasUnorphaned: flags&BFWasUnorphaned != 0,
|
||||
})
|
||||
if len(chainUpdates.addedChainBlockHashes) > 0 {
|
||||
dag.sendNotification(NTChainChanged, &ChainChangedNotificationData{
|
||||
RemovedChainBlockHashes: chainUpdates.removedChainBlockHashes,
|
||||
AddedChainBlockHashes: chainUpdates.addedChainBlockHashes,
|
||||
})
|
||||
}
|
||||
dag.dagLock.Lock()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func lookupParentNodes(block *util.Block, dag *BlockDAG) (blockSet, error) {
|
||||
header := block.MsgBlock().Header
|
||||
parentHashes := header.ParentHashes
|
||||
|
||||
nodes := newBlockSet()
|
||||
for _, parentHash := range parentHashes {
|
||||
node, ok := dag.index.LookupNode(parentHash)
|
||||
if !ok {
|
||||
str := fmt.Sprintf("parent block %s is unknown", parentHash)
|
||||
return nil, ruleError(ErrParentBlockUnknown, str)
|
||||
} else if dag.index.NodeStatus(node).KnownInvalid() {
|
||||
str := fmt.Sprintf("parent block %s is known to be invalid", parentHash)
|
||||
return nil, ruleError(ErrInvalidAncestorBlock, str)
|
||||
}
|
||||
|
||||
nodes.add(node)
|
||||
}
|
||||
|
||||
return nodes, nil
|
||||
}
|
||||
@@ -1,107 +0,0 @@
|
||||
package blockdag
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/kaspanet/kaspad/dagconfig"
|
||||
)
|
||||
|
||||
func TestMaybeAcceptBlockErrors(t *testing.T) {
|
||||
// Create a new database and DAG instance to run tests against.
|
||||
dag, teardownFunc, err := DAGSetup("TestMaybeAcceptBlockErrors", true, Config{
|
||||
DAGParams: &dagconfig.SimnetParams,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("TestMaybeAcceptBlockErrors: Failed to setup DAG instance: %v", err)
|
||||
}
|
||||
defer teardownFunc()
|
||||
|
||||
dag.TestSetCoinbaseMaturity(0)
|
||||
|
||||
// Test rejecting the block if its parents are missing
|
||||
orphanBlockFile := "blk_3B.dat"
|
||||
loadedBlocks, err := LoadBlocks(filepath.Join("testdata/", orphanBlockFile))
|
||||
if err != nil {
|
||||
t.Fatalf("TestMaybeAcceptBlockErrors: "+
|
||||
"Error loading file '%s': %s\n", orphanBlockFile, err)
|
||||
}
|
||||
block := loadedBlocks[0]
|
||||
|
||||
err = dag.maybeAcceptBlock(block, BFNone)
|
||||
if err == nil {
|
||||
t.Errorf("TestMaybeAcceptBlockErrors: rejecting the block if its parents are missing: "+
|
||||
"Expected: %s, got: <nil>", ErrParentBlockUnknown)
|
||||
}
|
||||
var ruleErr RuleError
|
||||
if ok := errors.As(err, &ruleErr); !ok {
|
||||
t.Errorf("TestMaybeAcceptBlockErrors: rejecting the block if its parents are missing: "+
|
||||
"Expected RuleError but got %s", err)
|
||||
} else if ruleErr.ErrorCode != ErrParentBlockUnknown {
|
||||
t.Errorf("TestMaybeAcceptBlockErrors: rejecting the block if its parents are missing: "+
|
||||
"Unexpected error code. Want: %s, got: %s", ErrParentBlockUnknown, ruleErr.ErrorCode)
|
||||
}
|
||||
|
||||
// Test rejecting the block if its parents are invalid
|
||||
blocksFile := "blk_0_to_4.dat"
|
||||
blocks, err := LoadBlocks(filepath.Join("testdata/", blocksFile))
|
||||
if err != nil {
|
||||
t.Fatalf("TestMaybeAcceptBlockErrors: "+
|
||||
"Error loading file '%s': %s\n", blocksFile, err)
|
||||
}
|
||||
|
||||
// Add a valid block and mark it as invalid
|
||||
block1 := blocks[1]
|
||||
isOrphan, isDelayed, err := dag.ProcessBlock(block1, BFNone)
|
||||
if err != nil {
|
||||
t.Fatalf("TestMaybeAcceptBlockErrors: Valid block unexpectedly returned an error: %s", err)
|
||||
}
|
||||
if isDelayed {
|
||||
t.Fatalf("TestMaybeAcceptBlockErrors: block 1 is too far in the future")
|
||||
}
|
||||
if isOrphan {
|
||||
t.Fatalf("TestMaybeAcceptBlockErrors: incorrectly returned block 1 is an orphan")
|
||||
}
|
||||
blockNode1, ok := dag.index.LookupNode(block1.Hash())
|
||||
if !ok {
|
||||
t.Fatalf("block %s does not exist in the DAG", block1.Hash())
|
||||
}
|
||||
dag.index.SetStatusFlags(blockNode1, statusValidateFailed)
|
||||
|
||||
block2 := blocks[2]
|
||||
err = dag.maybeAcceptBlock(block2, BFNone)
|
||||
if err == nil {
|
||||
t.Errorf("TestMaybeAcceptBlockErrors: rejecting the block if its parents are invalid: "+
|
||||
"Expected: %s, got: <nil>", ErrInvalidAncestorBlock)
|
||||
}
|
||||
if ok := errors.As(err, &ruleErr); !ok {
|
||||
t.Errorf("TestMaybeAcceptBlockErrors: rejecting the block if its parents are invalid: "+
|
||||
"Expected RuleError but got %s", err)
|
||||
} else if ruleErr.ErrorCode != ErrInvalidAncestorBlock {
|
||||
t.Errorf("TestMaybeAcceptBlockErrors: rejecting the block if its parents are invalid: "+
|
||||
"Unexpected error. Want: %s, got: %s", ErrInvalidAncestorBlock, ruleErr.ErrorCode)
|
||||
}
|
||||
|
||||
// Set block1's status back to valid for next tests
|
||||
dag.index.UnsetStatusFlags(blockNode1, statusValidateFailed)
|
||||
|
||||
// Test rejecting the block due to bad context
|
||||
originalBits := block2.MsgBlock().Header.Bits
|
||||
block2.MsgBlock().Header.Bits = 0
|
||||
err = dag.maybeAcceptBlock(block2, BFNone)
|
||||
if err == nil {
|
||||
t.Errorf("TestMaybeAcceptBlockErrors: rejecting the block due to bad context: "+
|
||||
"Expected: %s, got: <nil>", ErrUnexpectedDifficulty)
|
||||
}
|
||||
if ok := errors.As(err, &ruleErr); !ok {
|
||||
t.Errorf("TestMaybeAcceptBlockErrors: rejecting the block due to bad context: "+
|
||||
"Expected RuleError but got %s", err)
|
||||
} else if ruleErr.ErrorCode != ErrUnexpectedDifficulty {
|
||||
t.Errorf("TestMaybeAcceptBlockErrors: rejecting the block due to bad context: "+
|
||||
"Unexpected error. Want: %s, got: %s", ErrUnexpectedDifficulty, ruleErr.ErrorCode)
|
||||
}
|
||||
|
||||
// Set block2's bits back to valid for next tests
|
||||
block2.MsgBlock().Header.Bits = originalBits
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user