lnwire: replace all wire msg tests with a single property-based test

This commit does away with all the old manual message equality tests
and replace it with a single property-based test that uses the
testing/quick package. This test uses a single scenario which MUST hold
for all the messages type and all possible messages generated for those
types. As a result we are able to do away with all the prior manually
generated test data as the fuzzer to scan the input space looking for a
message that violates the scenario.
This commit is contained in:
Olaoluwa Osuntokun 2017-04-19 16:16:55 -07:00
parent febc8c399a
commit e3686cbc69
No known key found for this signature in database
GPG Key ID: 9CC5B105D03521A2
23 changed files with 583 additions and 853 deletions

View File

@ -1,34 +0,0 @@
package lnwire
import (
"bytes"
"reflect"
"testing"
)
func TestAnnounceSignatureEncodeDecode(t *testing.T) {
ac := &AnnounceSignatures{
ChannelID: ChannelID(revHash),
ShortChannelID: NewShortChanIDFromInt(1),
NodeSignature: someSig,
BitcoinSignature: someSig,
}
// Next encode the message into an empty bytes buffer.
var b bytes.Buffer
if err := ac.Encode(&b, 0); err != nil {
t.Fatalf("unable to encode AnnounceSignatures: %v", err)
}
// Deserialize the encoded message into a new empty struct.
ac2 := &AnnounceSignatures{}
if err := ac2.Decode(&b, 0); err != nil {
t.Fatalf("unable to decode AnnounceSignatures: %v", err)
}
// Assert equality of the two instances.
if !reflect.DeepEqual(ac, ac2) {
t.Fatalf("encode/decode error messages don't match %#v vs %#v",
ac, ac2)
}
}

View File

@ -1,89 +0,0 @@
package lnwire
import (
"bytes"
"reflect"
"testing"
"github.com/roasbeef/btcd/btcec"
"github.com/roasbeef/btcd/chaincfg/chainhash"
)
func TestChannelAnnoucementEncodeDecode(t *testing.T) {
ca := &ChannelAnnouncement{
NodeSig1: someSig,
NodeSig2: someSig,
ShortChannelID: someShortChannelID,
BitcoinSig1: someSig,
BitcoinSig2: someSig,
NodeID1: pubKey,
NodeID2: pubKey,
BitcoinKey1: pubKey,
BitcoinKey2: pubKey,
}
// Next encode the CA message into an empty bytes buffer.
var b bytes.Buffer
if err := ca.Encode(&b, 0); err != nil {
t.Fatalf("unable to encode ChannelAnnouncement: %v", err)
}
// Ensure the max payload estimate is correct.
serializedLength := uint32(b.Len())
if serializedLength != ca.MaxPayloadLength(0) {
t.Fatalf("payload length estimate is incorrect: expected %v "+
"got %v", serializedLength, ca.MaxPayloadLength(0))
}
// Deserialize the encoded CA message into a new empty struct.
ca2 := &ChannelAnnouncement{}
if err := ca2.Decode(&b, 0); err != nil {
t.Fatalf("unable to decode ChannelAnnouncement: %v", err)
}
// Assert equality of the two instances.
if !reflect.DeepEqual(ca, ca2) {
t.Fatalf("encode/decode error messages don't match %#v vs %#v",
ca, ca2)
}
}
func TestChannelAnnoucementValidation(t *testing.T) {
getKeys := func(s string) (*btcec.PrivateKey, *btcec.PublicKey) {
return btcec.PrivKeyFromBytes(btcec.S256(), []byte(s))
}
firstNodePrivKey, firstNodePubKey := getKeys("node-id-1")
secondNodePrivKey, secondNodePubKey := getKeys("node-id-2")
firstBitcoinPrivKey, firstBitcoinPubKey := getKeys("bitcoin-key-1")
secondBitcoinPrivKey, secondBitcoinPubKey := getKeys("bitcoin-key-2")
hash := chainhash.DoubleHashB(firstNodePubKey.SerializeCompressed())
firstBitcoinSig, _ := firstBitcoinPrivKey.Sign(hash)
hash = chainhash.DoubleHashB(secondNodePubKey.SerializeCompressed())
secondBitcoinSig, _ := secondBitcoinPrivKey.Sign(hash)
ca := &ChannelAnnouncement{
ShortChannelID: someShortChannelID,
BitcoinSig1: firstBitcoinSig,
BitcoinSig2: secondBitcoinSig,
NodeID1: firstNodePubKey,
NodeID2: secondNodePubKey,
BitcoinKey1: firstBitcoinPubKey,
BitcoinKey2: secondBitcoinPubKey,
}
dataToSign, _ := ca.DataToSign()
hash = chainhash.DoubleHashB(dataToSign)
firstNodeSign, _ := firstNodePrivKey.Sign(hash)
ca.NodeSig1 = firstNodeSign
secondNodeSign, _ := secondNodePrivKey.Sign(hash)
ca.NodeSig2 = secondNodeSign
if err := ca.Validate(); err != nil {
t.Fatal(err)
}
}

View File

@ -1,45 +0,0 @@
package lnwire
import (
"bytes"
"reflect"
"testing"
)
func TestChannelUpdateEncodeDecode(t *testing.T) {
cua := &ChannelUpdate{
Signature: someSig,
ShortChannelID: someShortChannelID,
Timestamp: maxUint32,
Flags: maxUint16,
TimeLockDelta: maxUint16,
HtlcMinimumMsat: maxUint32,
FeeBaseMsat: maxUint32,
FeeProportionalMillionths: maxUint32,
}
// Next encode the CUA message into an empty bytes buffer.
var b bytes.Buffer
if err := cua.Encode(&b, 0); err != nil {
t.Fatalf("unable to encode ChannelUpdate: %v", err)
}
// Ensure the max payload estimate is correct.
serializedLength := uint32(b.Len())
if serializedLength != cua.MaxPayloadLength(0) {
t.Fatalf("payload length estimate is incorrect: expected %v "+
"got %v", serializedLength, cua.MaxPayloadLength(0))
}
// Deserialize the encoded CUA message into a new empty struct.
cua2 := &ChannelUpdate{}
if err := cua2.Decode(&b, 0); err != nil {
t.Fatalf("unable to decode ChannelUpdateAnnouncement: %v", err)
}
// Assert equality of the two instances.
if !reflect.DeepEqual(cua, cua2) {
t.Fatalf("encode/decode error messages don't match %#v vs %#v",
cua, cua2)
}
}

View File

@ -26,12 +26,6 @@ type CloseComplete struct {
ResponderCloseSig *btcec.Signature
}
// NewCloseComplete creates a new empty CloseComplete message.
// TODO(roasbeef): add params to all constructors...
func NewCloseComplete() *CloseComplete {
return &CloseComplete{}
}
// A compile time check to ensure CloseComplete implements the lnwire.Message
// interface.
var _ Message = (*CloseComplete)(nil)

View File

@ -1,32 +0,0 @@
package lnwire
import (
"bytes"
"reflect"
"testing"
)
func TestCloseCompleteEncodeDecode(t *testing.T) {
cc := &CloseComplete{
ChannelPoint: *outpoint1,
ResponderCloseSig: commitSig,
}
// Next encode the CC message into an empty bytes buffer.
var b bytes.Buffer
if err := cc.Encode(&b, 0); err != nil {
t.Fatalf("unable to encode CloseComplete: %v", err)
}
// Deserialize the encoded CC message into a new empty struct.
cc2 := &CloseComplete{}
if err := cc2.Decode(&b, 0); err != nil {
t.Fatalf("unable to decode CloseComplete: %v", err)
}
// Assert equality of the two instances.
if !reflect.DeepEqual(cc, cc2) {
t.Fatalf("encode/decode error messages don't match %#v vs %#v",
cc, cc2)
}
}

View File

@ -1,35 +0,0 @@
package lnwire
import (
"bytes"
"reflect"
"testing"
"github.com/roasbeef/btcutil"
)
func TestCloseRequestEncodeDecode(t *testing.T) {
cr := &CloseRequest{
ChanID: ChannelID(revHash),
RequesterCloseSig: commitSig,
Fee: btcutil.Amount(10000),
}
// Next encode the CR message into an empty bytes buffer.
var b bytes.Buffer
if err := cr.Encode(&b, 0); err != nil {
t.Fatalf("unable to encode CloseRequest: %v", err)
}
// Deserialize the encoded CR message into a new empty struct.
cr2 := &CloseRequest{}
if err := cr2.Decode(&b, 0); err != nil {
t.Fatalf("unable to decode CloseRequest: %v", err)
}
// Assert equality of the two instances.
if !reflect.DeepEqual(cr, cr2) {
t.Fatalf("encode/decode error messages don't match %#v vs %#v",
cr, cr2)
}
}

View File

@ -1,32 +0,0 @@
package lnwire
import (
"bytes"
"reflect"
"testing"
)
func TestCommitSigEncodeDecode(t *testing.T) {
commitSignature := &CommitSig{
ChanID: ChannelID(revHash),
CommitSig: commitSig,
}
// Next encode the CS message into an empty bytes buffer.
var b bytes.Buffer
if err := commitSignature.Encode(&b, 0); err != nil {
t.Fatalf("unable to encode CommitSig: %v", err)
}
// Deserialize the encoded EG message into a new empty struct.
commitSignature2 := &CommitSig{}
if err := commitSignature2.Decode(&b, 0); err != nil {
t.Fatalf("unable to decode CommitSig: %v", err)
}
// Assert equality of the two instances.
if !reflect.DeepEqual(commitSignature, commitSignature2) {
t.Fatalf("encode/decode error messages don't match %#v vs %#v",
commitSignature, commitSignature2)
}
}

View File

@ -1,33 +0,0 @@
package lnwire
import (
"bytes"
"reflect"
"testing"
)
func TestErrorEncodeDecode(t *testing.T) {
eg := &Error{
ChanID: ChannelID(revHash),
Code: 99,
Data: []byte{'k', 'e', 'k'},
}
// Next encode the error message into an empty bytes buffer.
var b bytes.Buffer
if err := eg.Encode(&b, 0); err != nil {
t.Fatalf("unable to encode ErrorGeneric: %v", err)
}
// Deserialize the encoded error message into a new empty struct.
eg2 := &Error{}
if err := eg2.Decode(&b, 0); err != nil {
t.Fatalf("unable to decode ErrorGeneric: %v", err)
}
// Assert equality of the two instances.
if !reflect.DeepEqual(eg, eg2) {
t.Fatalf("encode/decode error messages don't match %#v vs %#v",
eg, eg2)
}
}

View File

@ -72,6 +72,11 @@ func TestOptionalFeature(t *testing.T) {
t.Fatal("locally feature was set but remote peer notified us" +
" that it don't have it")
}
// A feature with a non-existent name shouldn't be active.
if shared.IsActive("nothere") {
t.Fatal("non-existent feature shouldn't be active")
}
}
// TestSetRequireAfterInit checks that we can change the feature flag after
@ -117,3 +122,21 @@ func TestDecodeEncodeFeaturesVector(t *testing.T) {
"%v", spew.Sdump(f), spew.Sdump(nf))
}
}
func TestFeatureFlagString(t *testing.T) {
if OptionalFlag.String() != "optional" {
t.Fatalf("incorrect string, expected optional got %v",
OptionalFlag.String())
}
if RequiredFlag.String() != "required" {
t.Fatalf("incorrect string, expected required got %v",
OptionalFlag.String())
}
fakeFlag := featureFlag(9)
if fakeFlag.String() != "<unknown>" {
t.Fatalf("incorrect string, expected <unknown> got %v",
fakeFlag.String())
}
}

View File

@ -1,35 +0,0 @@
package lnwire
import (
"bytes"
"reflect"
"testing"
)
func TestFundingLockedWire(t *testing.T) {
// First create a new FundingLocked message.
fl := NewFundingLocked(ChannelID(revHash), pubKey)
// Next encode the FundingLocked message into an empty bytes buffer.
var b bytes.Buffer
if err := fl.Encode(&b, 0); err != nil {
t.Fatalf("unable to encode FundingLocked: %v", err)
}
// Check to ensure that the FundingLocked message is the correct size.
if uint32(b.Len()) > fl.MaxPayloadLength(0) {
t.Fatalf("length of FundingLocked message is too long: %v should be less than %v",
b.Len(), fl.MaxPayloadLength(0))
}
// Deserialize the encoded FundingLocked message into an empty struct.
fl2 := &FundingLocked{}
if err := fl2.Decode(&b, 0); err != nil {
t.Fatalf("unable to decode FundingLocked: %v", err)
}
// Assert equality of the two instances
if !reflect.DeepEqual(fl, fl2) {
t.Fatalf("encode/decode error messages don't match %#v vs %#v", fl, fl2)
}
}

View File

@ -1,47 +0,0 @@
package lnwire
import (
"bytes"
"reflect"
"testing"
)
func TestInitEncodeDecode(t *testing.T) {
const somefeature = "somefeature"
gf := NewFeatureVector([]Feature{
{somefeature, OptionalFlag},
})
lf := NewFeatureVector([]Feature{
{somefeature, OptionalFlag},
})
init1 := &Init{
GlobalFeatures: gf,
LocalFeatures: lf,
}
// Next encode the init message into an empty bytes buffer.
var b bytes.Buffer
if err := init1.Encode(&b, 0); err != nil {
t.Fatalf("unable to encode init: %v", err)
}
// Deserialize the encoded init message into a new empty struct.
init2 := &Init{}
if err := init2.Decode(&b, 0); err != nil {
t.Fatalf("unable to decode init: %v", err)
}
// We not encode the feature map in feature vector, for that reason the
// init messages will differ. Set feature map with nil in
// order to use deep equal function.
init1.GlobalFeatures.featuresMap = nil
init1.LocalFeatures.featuresMap = nil
// Assert equality of the two instances.
if !reflect.DeepEqual(init1, init2) {
t.Fatalf("encode/decode init messages don't match %#v vs %#v",
init1, init2)
}
}

View File

@ -1,16 +1,22 @@
package lnwire
import (
"bytes"
"encoding/hex"
"math"
"math/big"
"math/rand"
"net"
"reflect"
"testing"
"testing/quick"
"github.com/roasbeef/btcd/btcec"
"github.com/roasbeef/btcd/chaincfg/chainhash"
"github.com/roasbeef/btcd/txscript"
"github.com/roasbeef/btcd/wire"
"github.com/roasbeef/btcutil"
)
// Common variables and functions for the message tests
var (
revHash = [32]byte{
0xb7, 0x94, 0x38, 0x5f, 0x2d, 0x1e, 0xf7, 0xab,
@ -22,62 +28,551 @@ var (
shaHash1Bytes, _ = hex.DecodeString("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855")
shaHash1, _ = chainhash.NewHash(shaHash1Bytes)
outpoint1 = wire.NewOutPoint(shaHash1, 0)
privKeyBytes, _ = hex.DecodeString("9fa1d55217f57019a3c37f49465896b15836f54cb8ef6963870a52926420a2dd")
privKey, pubKey = btcec.PrivKeyFromBytes(btcec.S256(), privKeyBytes)
address = pubKey
// Commitment Signature
tx = wire.NewMsgTx(1)
emptybytes = new([]byte)
sigStr, _ = txscript.RawTxInSignature(tx, 0, *emptybytes, txscript.SigHashAll, privKey)
commitSig, _ = btcec.ParseSignature(sigStr, btcec.S256())
sig1privKeyBytes, _ = hex.DecodeString("927f5827d75dd2addeb532c0fa5ac9277565f981dd6d0d037b422be5f60bdbef")
sig1privKey, _ = btcec.PrivKeyFromBytes(btcec.S256(), sig1privKeyBytes)
sigStr1, _ = txscript.RawTxInSignature(tx, 0, *emptybytes, txscript.SigHashAll, sig1privKey)
commitSig1, _ = btcec.ParseSignature(sigStr1, btcec.S256())
// Funding TX Sig 2
sig2privKeyBytes, _ = hex.DecodeString("8a4ad188f6f4000495b765cfb6ffa591133a73019c45428ddd28f53bab551847")
sig2privKey, _ = btcec.PrivKeyFromBytes(btcec.S256(), sig2privKeyBytes)
sigStr2, _ = txscript.RawTxInSignature(tx, 0, *emptybytes, txscript.SigHashAll, sig2privKey)
commitSig2, _ = btcec.ParseSignature(sigStr2, btcec.S256())
// Slice of Funding TX Sigs
ptrFundingTXSigs = append(*new([]*btcec.Signature), commitSig1, commitSig2)
// TxID
txid = new(chainhash.Hash)
// Reversed when displayed
txidBytes, _ = hex.DecodeString("fd95c6e5c9d5bcf9cfc7231b6a438e46c518c724d0b04b75cc8fddf84a254e3a")
_ = copy(txid[:], txidBytes)
someAlias, _ = NewAlias("012345678901234567890")
someSig, _ = btcec.ParseSignature(sigStr, btcec.S256())
someSigBytes = someSig.Serialize()
someAddress = &net.TCPAddr{IP: (net.IP)([]byte{0x7f, 0x0, 0x0, 0x1}), Port: 8333}
someOtherAddress, _ = net.ResolveTCPAddr("tcp", "[2001:db8:85a3:0:0:8a2e:370:7334]:80")
someAddresses = []net.Addr{someAddress, someOtherAddress}
maxUint32 uint32 = (1 << 32) - 1
maxUint24 uint32 = (1 << 24) - 1
maxUint16 uint16 = (1 << 16) - 1
someShortChannelID = ShortChannelID{
BlockHeight: maxUint24,
TxIndex: maxUint24,
TxPosition: maxUint16,
testSig = &btcec.Signature{
R: new(big.Int),
S: new(big.Int),
}
_, _ = testSig.R.SetString("63724406601629180062774974542967536251589935445068131219452686511677818569431", 10)
_, _ = testSig.S.SetString("18801056069249825825291287104931333862866033135609736119018462340006816851118", 10)
someRGB = RGB{
red: 255,
green: 255,
blue: 255,
}
someFeature = featureName("somefeature")
someFeatures = NewFeatureVector([]Feature{
{someFeature, OptionalFlag},
})
// TODO(roasbeef): randomly generate from three types of addrs
a1 = &net.TCPAddr{IP: (net.IP)([]byte{0x7f, 0x0, 0x0, 0x1}), Port: 8333}
a2, _ = net.ResolveTCPAddr("tcp", "[2001:db8:85a3:0:0:8a2e:370:7334]:80")
testAddrs = []net.Addr{a1, a2}
)
func randPubKey() (*btcec.PublicKey, error) {
priv, err := btcec.NewPrivateKey(btcec.S256())
if err != nil {
return nil, err
}
return priv.PubKey(), nil
}
func randFeatureVector(r *rand.Rand) *FeatureVector {
numFeatures := r.Int31n(131123)
features := make([]Feature, numFeatures)
for i := int32(0); i < numFeatures; i++ {
features[i] = Feature{
Flag: featureFlag(rand.Int31n(2) + 1),
}
}
return NewFeatureVector(features)
}
func TestMaxOutPointIndex(t *testing.T) {
op := wire.OutPoint{
Index: math.MaxUint32,
}
var b bytes.Buffer
if err := writeElement(&b, op); err == nil {
t.Fatalf("write of outPoint should fail, index exceeds 16-bits")
}
}
func TestEmptyMessageUnknownType(t *testing.T) {
fakeType := MessageType(math.MaxUint16)
if _, err := makeEmptyMessage(fakeType); err == nil {
t.Fatalf("should not be able to make an empty message of an " +
"unknown type")
}
}
// TestLightningWireProtocol uses the testing/quick package to create a series
// of fuzz tests to attempt to break a primary scenario which is implemented as
// property based testing scenario.
func TestLightningWireProtocol(t *testing.T) {
// mainScenario is the primary test that will programmatically be
// executed for all registered wire messages. The quick-checker within
// testing/quick will attempt to find an input to this function, s.t
// the function returns false, if so then we've found an input that
// violates our model of the system.
mainScenario := func(msg Message) bool {
// Give a new message, we'll serialize the message into a new
// bytes buffer.
var b bytes.Buffer
if _, err := WriteMessage(&b, msg, 0); err != nil {
t.Fatalf("unable to write msg: %v", err)
return false
}
// Next, we'll ensure that the serialized payload (subtracting
// the 2 bytes for the message type) is _below_ the specified
// max payload size for this message.
payloadLen := uint32(b.Len()) - 2
if payloadLen > msg.MaxPayloadLength(0) {
t.Fatalf("msg payload constraint violated: %v > %v",
payloadLen, msg.MaxPayloadLength(0))
return false
}
// Finally, we'll deserialize the message from the written
// buffer, and finally assert that the messages are equal.
_, newMsg, err := ReadMessage(&b, 0)
if err != nil {
t.Fatalf("unable to read msg: %v", err)
return false
}
if !reflect.DeepEqual(msg, newMsg) {
t.Fatalf("messages don't match after re-encoding: %v "+
"vs %v", msg, newMsg)
return false
}
return true
}
// customTypeGen is a map of functions that are able to randomly
// generate a given type. These functions are needed for types which
// are too complex for the testing/quick package to automatically
// generate.
customTypeGen := map[MessageType]func([]reflect.Value, *rand.Rand){
MsgInit: func(v []reflect.Value, r *rand.Rand) {
req := NewInitMessage(
randFeatureVector(r),
randFeatureVector(r),
)
req.GlobalFeatures.featuresMap = nil
req.LocalFeatures.featuresMap = nil
v[0] = reflect.ValueOf(*req)
},
MsgSingleFundingRequest: func(v []reflect.Value, r *rand.Rand) {
req := SingleFundingRequest{
ChannelType: uint8(r.Int63()),
CoinType: uint64(r.Int63()),
FeePerKb: btcutil.Amount(r.Int63()),
FundingAmount: btcutil.Amount(r.Int63()),
PushSatoshis: btcutil.Amount(r.Int63()),
CsvDelay: uint32(r.Int31()),
DustLimit: btcutil.Amount(r.Int63()),
ConfirmationDepth: uint32(r.Int31()),
}
if _, err := r.Read(req.PendingChannelID[:]); err != nil {
t.Fatalf("unable to generate pending chan id: %v", err)
return
}
var script [34]byte
if _, err := r.Read(script[:]); err != nil {
t.Fatalf("unable to generate pending chan id: %v", err)
return
}
req.DeliveryPkScript = script[:]
var err error
req.ChannelDerivationPoint, err = randPubKey()
if err != nil {
t.Fatalf("unable to generate key: %v", err)
return
}
req.CommitmentKey, err = randPubKey()
if err != nil {
t.Fatalf("unable to generate key: %v", err)
return
}
v[0] = reflect.ValueOf(req)
},
MsgSingleFundingResponse: func(v []reflect.Value, r *rand.Rand) {
req := SingleFundingResponse{
CsvDelay: uint32(r.Int31()),
DustLimit: btcutil.Amount(r.Int63()),
ConfirmationDepth: uint32(r.Int31()),
}
if _, err := r.Read(req.PendingChannelID[:]); err != nil {
t.Fatalf("unable to generate pending chan id: %v", err)
return
}
var script [34]byte
if _, err := r.Read(script[:]); err != nil {
t.Fatalf("unable to generate pending chan id: %v", err)
return
}
req.DeliveryPkScript = script[:]
var err error
req.ChannelDerivationPoint, err = randPubKey()
if err != nil {
t.Fatalf("unable to generate key: %v", err)
return
}
req.CommitmentKey, err = randPubKey()
if err != nil {
t.Fatalf("unable to generate key: %v", err)
return
}
req.RevocationKey, err = randPubKey()
if err != nil {
t.Fatalf("unable to generate key: %v", err)
return
}
v[0] = reflect.ValueOf(req)
},
MsgSingleFundingComplete: func(v []reflect.Value, r *rand.Rand) {
req := SingleFundingComplete{}
if _, err := r.Read(req.PendingChannelID[:]); err != nil {
t.Fatalf("unable to generate pending chan id: %v", err)
return
}
if _, err := r.Read(req.FundingOutPoint.Hash[:]); err != nil {
t.Fatalf("unable to generate hash: %v", err)
return
}
req.FundingOutPoint.Index = uint32(r.Int31()) % math.MaxUint16
if _, err := r.Read(req.StateHintObsfucator[:]); err != nil {
t.Fatalf("unable to read state hint: %v", err)
return
}
req.CommitSignature = testSig
var err error
req.RevocationKey, err = randPubKey()
if err != nil {
t.Fatalf("unable to generate key: %v", err)
return
}
v[0] = reflect.ValueOf(req)
},
MsgSingleFundingSignComplete: func(v []reflect.Value, r *rand.Rand) {
var c [32]byte
if _, err := r.Read(c[:]); err != nil {
t.Fatalf("unable to generate chan id: %v", err)
return
}
req := NewSingleFundingSignComplete(ChannelID(c), testSig)
v[0] = reflect.ValueOf(*req)
},
MsgFundingLocked: func(v []reflect.Value, r *rand.Rand) {
var c [32]byte
if _, err := r.Read(c[:]); err != nil {
t.Fatalf("unable to generate chan id: %v", err)
return
}
pubKey, err := randPubKey()
if err != nil {
t.Fatalf("unable to generate key: %v", err)
return
}
req := NewFundingLocked(ChannelID(c), pubKey)
v[0] = reflect.ValueOf(*req)
},
MsgCloseRequest: func(v []reflect.Value, r *rand.Rand) {
var chanID [32]byte
if _, err := r.Read(chanID[:]); err != nil {
t.Fatalf("unable to generate chan id: %v", err)
return
}
req := NewCloseRequest(ChannelID(chanID), testSig)
req.Fee = btcutil.Amount(rand.Int63())
req.RequesterCloseSig = testSig
v[0] = reflect.ValueOf(*req)
},
MsgCloseComplete: func(v []reflect.Value, r *rand.Rand) {
req := CloseComplete{}
if _, err := r.Read(req.ChannelPoint.Hash[:]); err != nil {
t.Fatalf("unable to generate hash: %v", err)
return
}
req.ChannelPoint.Index = uint32(r.Int31()) % math.MaxUint16
req.ResponderCloseSig = testSig
v[0] = reflect.ValueOf(req)
},
MsgCommitSig: func(v []reflect.Value, r *rand.Rand) {
req := NewCommitSig()
if _, err := r.Read(req.ChanID[:]); err != nil {
t.Fatalf("unable to generate chan id: %v", err)
return
}
req.CommitSig = testSig
v[0] = reflect.ValueOf(*req)
},
MsgRevokeAndAck: func(v []reflect.Value, r *rand.Rand) {
req := NewRevokeAndAck()
if _, err := r.Read(req.ChanID[:]); err != nil {
t.Fatalf("unable to generate chan id: %v", err)
return
}
if _, err := r.Read(req.Revocation[:]); err != nil {
t.Fatalf("unable to generate bytes: %v", err)
return
}
if _, err := r.Read(req.NextRevocationHash[:]); err != nil {
t.Fatalf("unable to generate bytes: %v", err)
return
}
var err error
req.NextRevocationKey, err = randPubKey()
if err != nil {
t.Fatalf("unable to generate key: %v", err)
return
}
v[0] = reflect.ValueOf(*req)
},
MsgChannelAnnouncement: func(v []reflect.Value, r *rand.Rand) {
req := ChannelAnnouncement{
ShortChannelID: NewShortChanIDFromInt(uint64(r.Int63())),
}
req.NodeSig1 = testSig
req.NodeSig2 = testSig
req.BitcoinSig1 = testSig
req.BitcoinSig2 = testSig
var err error
req.NodeID1, err = randPubKey()
if err != nil {
t.Fatalf("unable to generate key: %v", err)
return
}
req.NodeID2, err = randPubKey()
if err != nil {
t.Fatalf("unable to generate key: %v", err)
return
}
req.BitcoinKey1, err = randPubKey()
if err != nil {
t.Fatalf("unable to generate key: %v", err)
return
}
req.BitcoinKey2, err = randPubKey()
if err != nil {
t.Fatalf("unable to generate key: %v", err)
return
}
v[0] = reflect.ValueOf(req)
},
MsgNodeAnnouncement: func(v []reflect.Value, r *rand.Rand) {
var a [32]byte
if _, err := r.Read(a[:]); err != nil {
t.Fatalf("unable to generate alias: %v", err)
return
}
req := NodeAnnouncement{
Signature: testSig,
Timestamp: uint32(r.Int31()),
Alias: newAlias(a[:]),
RGBColor: RGB{
red: uint8(r.Int31()),
green: uint8(r.Int31()),
blue: uint8(r.Int31()),
},
Features: randFeatureVector(r),
Addresses: testAddrs,
}
req.Features.featuresMap = nil
var err error
req.NodeID, err = randPubKey()
if err != nil {
t.Fatalf("unable to generate key: %v", err)
return
}
v[0] = reflect.ValueOf(req)
},
MsgChannelUpdate: func(v []reflect.Value, r *rand.Rand) {
req := ChannelUpdate{
Signature: testSig,
ShortChannelID: NewShortChanIDFromInt(uint64(r.Int63())),
Timestamp: uint32(r.Int31()),
Flags: uint16(r.Int31()),
TimeLockDelta: uint16(r.Int31()),
HtlcMinimumMsat: uint32(r.Int31()),
FeeBaseMsat: uint32(r.Int31()),
FeeProportionalMillionths: uint32(r.Int31()),
}
v[0] = reflect.ValueOf(req)
},
MsgAnnounceSignatures: func(v []reflect.Value, r *rand.Rand) {
req := AnnounceSignatures{
ShortChannelID: NewShortChanIDFromInt(uint64(r.Int63())),
NodeSignature: testSig,
BitcoinSignature: testSig,
}
if _, err := r.Read(req.ChannelID[:]); err != nil {
t.Fatalf("unable to generate chan id: %v", err)
return
}
v[0] = reflect.ValueOf(req)
},
}
// With the above types defined, we'll now generate a slice of
// scenarios to feed into quick.Check. The function scans in input
// space of the target function under test, so we'll need to create a
// series of wrapper functions to force it to iterate over the target
// types, but re-use the mainScenario defined above.
tests := []struct {
msgType MessageType
scenario interface{}
}{
{
msgType: MsgInit,
scenario: func(m Init) bool {
return mainScenario(&m)
},
},
{
msgType: MsgError,
scenario: func(m Error) bool {
return mainScenario(&m)
},
},
{
msgType: MsgPing,
scenario: func(m Ping) bool {
return mainScenario(&m)
},
},
{
msgType: MsgPong,
scenario: func(m Pong) bool {
return mainScenario(&m)
},
},
{
msgType: MsgSingleFundingRequest,
scenario: func(m SingleFundingRequest) bool {
return mainScenario(&m)
},
},
{
msgType: MsgSingleFundingResponse,
scenario: func(m SingleFundingResponse) bool {
return mainScenario(&m)
},
},
{
msgType: MsgSingleFundingComplete,
scenario: func(m SingleFundingComplete) bool {
return mainScenario(&m)
},
},
{
msgType: MsgSingleFundingSignComplete,
scenario: func(m SingleFundingSignComplete) bool {
return mainScenario(&m)
},
},
{
msgType: MsgFundingLocked,
scenario: func(m FundingLocked) bool {
return mainScenario(&m)
},
},
{
msgType: MsgCloseRequest,
scenario: func(m CloseRequest) bool {
return mainScenario(&m)
},
},
{
msgType: MsgCloseComplete,
scenario: func(m CloseComplete) bool {
return mainScenario(&m)
},
},
{
msgType: MsgUpdateAddHTLC,
scenario: func(m UpdateAddHTLC) bool {
return mainScenario(&m)
},
},
{
msgType: MsgUpdateFufillHTLC,
scenario: func(m UpdateFufillHTLC) bool {
return mainScenario(&m)
},
},
{
msgType: MsgUpdateFailHTLC,
scenario: func(m UpdateFailHTLC) bool {
return mainScenario(&m)
},
},
{
msgType: MsgCommitSig,
scenario: func(m CommitSig) bool {
return mainScenario(&m)
},
},
{
msgType: MsgRevokeAndAck,
scenario: func(m RevokeAndAck) bool {
return mainScenario(&m)
},
},
{
msgType: MsgChannelAnnouncement,
scenario: func(m ChannelAnnouncement) bool {
return mainScenario(&m)
},
},
{
msgType: MsgNodeAnnouncement,
scenario: func(m NodeAnnouncement) bool {
return mainScenario(&m)
},
},
{
msgType: MsgChannelUpdate,
scenario: func(m ChannelUpdate) bool {
return mainScenario(&m)
},
},
{
msgType: MsgAnnounceSignatures,
scenario: func(m AnnounceSignatures) bool {
return mainScenario(&m)
},
},
}
for _, test := range tests {
var config *quick.Config
// If the type defined is within the custom type gen map above,
// then we'll modify the default config to use this Value
// function that knows how to generate the proper types.
if valueGen, ok := customTypeGen[test.msgType]; ok {
config = &quick.Config{
Values: valueGen,
}
}
t.Logf("Running fuzz tests for msgType=%v", test.msgType)
if err := quick.Check(test.scenario, config); err != nil {
t.Fatalf("fuzz checks for msg=%v failed: %v",
test.msgType, err)
}
}
}

View File

@ -1,76 +1,14 @@
package lnwire
import (
"bytes"
"reflect"
"testing"
)
func TestNodeAnnouncementEncodeDecode(t *testing.T) {
na := &NodeAnnouncement{
Signature: someSig,
Timestamp: maxUint32,
NodeID: pubKey,
RGBColor: someRGB,
Alias: someAlias,
Addresses: someAddresses,
Features: someFeatures,
}
// Next encode the NA message into an empty bytes buffer.
var b bytes.Buffer
if err := na.Encode(&b, 0); err != nil {
t.Fatalf("unable to encode NodeAnnouncement: %v", err)
}
// Deserialize the encoded NA message into a new empty struct.
na2 := &NodeAnnouncement{}
if err := na2.Decode(&b, 0); err != nil {
t.Fatalf("unable to decode NodeAnnouncement: %v", err)
}
// We do not encode the feature map in feature vector, for that reason
// the node announcement messages will differ. Set feature map with nil
// in order to use deep equal function.
na.Features.featuresMap = nil
// Assert equality of the two instances.
if !reflect.DeepEqual(na, na2) {
t.Fatalf("encode/decode error messages don't match %#v vs %#v",
na, na2)
}
}
func TestNodeAnnoucementPayloadLength(t *testing.T) {
na := &NodeAnnouncement{
Signature: someSig,
Timestamp: maxUint32,
NodeID: pubKey,
RGBColor: someRGB,
Alias: someAlias,
Addresses: someAddresses,
Features: someFeatures,
}
var b bytes.Buffer
if err := na.Encode(&b, 0); err != nil {
t.Fatalf("unable to encode node: %v", err)
}
serializedLength := uint32(b.Len())
if serializedLength != 167 {
t.Fatalf("payload length estimate is incorrect: expected %v "+
"got %v", 167, serializedLength)
}
if na.MaxPayloadLength(0) != 8192 {
t.Fatalf("max payload length doesn't match: expected 8192, got %v",
na.MaxPayloadLength(0))
}
}
import "testing"
func TestValidateAlias(t *testing.T) {
if err := someAlias.Validate(); err != nil {
aliasStr := "012345678901234567890"
alias := NewAlias(aliasStr)
if err := alias.Validate(); err != nil {
t.Fatalf("alias was invalid: %v", err)
}
if aliasStr != alias.String() {
t.Fatalf("aliases don't match")
}
}

View File

@ -1,32 +0,0 @@
package lnwire
import (
"bytes"
"reflect"
"testing"
)
func TestPingEncodeDecode(t *testing.T) {
ping := &Ping{
NumPongBytes: 10,
PaddingBytes: bytes.Repeat([]byte("A"), 100),
}
// Next encode the ping message into an empty bytes buffer.
var b bytes.Buffer
if err := ping.Encode(&b, 0); err != nil {
t.Fatalf("unable to encode ping: %v", err)
}
// Deserialize the encoded ping message into a new empty struct.
ping2 := &Ping{}
if err := ping2.Decode(&b, 0); err != nil {
t.Fatalf("unable to decode ping: %v", err)
}
// Assert equality of the two instances.
if !reflect.DeepEqual(ping, ping2) {
t.Fatalf("encode/decode ping messages don't match %#v vs %#v",
ping, ping2)
}
}

View File

@ -1,31 +0,0 @@
package lnwire
import (
"bytes"
"reflect"
"testing"
)
func TestPongEncodeDecode(t *testing.T) {
pong := &Pong{
PongBytes: bytes.Repeat([]byte("A"), 100),
}
// Next encode the pong message into an empty bytes buffer.
var b bytes.Buffer
if err := pong.Encode(&b, 0); err != nil {
t.Fatalf("unable to encode pong: %v", err)
}
// Deserialize the encoded pong message into a new empty struct.
pong2 := &Pong{}
if err := pong2.Decode(&b, 0); err != nil {
t.Fatalf("unable to decode ping: %v", err)
}
// Assert equality of the two instances.
if !reflect.DeepEqual(pong, pong2) {
t.Fatalf("encode/decode pong messages don't match %#v vs %#v",
pong, pong2)
}
}

View File

@ -1,34 +0,0 @@
package lnwire
import (
"bytes"
"reflect"
"testing"
)
func TestRevokeAndAckEncodeDecode(t *testing.T) {
cr := &RevokeAndAck{
ChanID: ChannelID(revHash),
Revocation: revHash,
NextRevocationKey: pubKey,
NextRevocationHash: revHash,
}
// Next encode the CR message into an empty bytes buffer.
var b bytes.Buffer
if err := cr.Encode(&b, 0); err != nil {
t.Fatalf("unable to encode RevokeAndAck: %v", err)
}
// Deserialize the encoded EG message into a new empty struct.
cr2 := &RevokeAndAck{}
if err := cr2.Decode(&b, 0); err != nil {
t.Fatalf("unable to decode RevokeAndAck: %v", err)
}
// Assert equality of the two instances.
if !reflect.DeepEqual(cr, cr2) {
t.Fatalf("encode/decode error messages don't match %#v vs %#v",
cr, cr2)
}
}

View File

@ -1,34 +0,0 @@
package lnwire
import (
"bytes"
"reflect"
"testing"
)
func TestSingleFundingCompleteWire(t *testing.T) {
var obsfucator [6]byte
copy(obsfucator[:], bytes.Repeat([]byte("k"), 6))
// First create a new SFC message.
sfc := NewSingleFundingComplete(revHash, *outpoint1, commitSig1, pubKey,
obsfucator)
// Next encode the SFC message into an empty bytes buffer.
var b bytes.Buffer
if err := sfc.Encode(&b, 0); err != nil {
t.Fatalf("unable to encode SingleFundingComplete: %v", err)
}
// Deserialize the encoded SFC message into a new empty struct.
sfc2 := &SingleFundingComplete{}
if err := sfc2.Decode(&b, 0); err != nil {
t.Fatalf("unable to decode SingleFundingComplete: %v", err)
}
// Assert equality of the two instances.
if !reflect.DeepEqual(sfc, sfc2) {
t.Fatalf("encode/decode error messages don't match %#v vs %#v",
sfc, sfc2)
}
}

View File

@ -1,33 +0,0 @@
package lnwire
import (
"bytes"
"reflect"
"testing"
)
func TestSingleFundingRequestWire(t *testing.T) {
// First create a new SFR message.
cdp := pubKey
delivery := PkScript(bytes.Repeat([]byte{0x02}, 25))
sfr := NewSingleFundingRequest(revHash, 21, 22, 23, 5, 5, cdp, cdp,
delivery, 540, 10000, 6)
// Next encode the SFR message into an empty bytes buffer.
var b bytes.Buffer
if err := sfr.Encode(&b, 0); err != nil {
t.Fatalf("unable to encode SingleFundingRequest: %v", err)
}
// Deserialize the encoded SFR message into a new empty struct.
sfr2 := &SingleFundingRequest{}
if err := sfr2.Decode(&b, 0); err != nil {
t.Fatalf("unable to decode SingleFundingRequest: %v", err)
}
// Assert equality of the two instances.
if !reflect.DeepEqual(sfr, sfr2) {
t.Fatalf("encode/decode error messages don't match %#v vs %#v",
sfr, sfr2)
}
}

View File

@ -1,32 +0,0 @@
package lnwire
import (
"bytes"
"reflect"
"testing"
)
func TestSingleFundingResponseWire(t *testing.T) {
// First create a new SFR message.
delivery := PkScript(bytes.Repeat([]byte{0x02}, 25))
sfr := NewSingleFundingResponse(revHash, pubKey, pubKey, pubKey, 5,
delivery, 540, 4)
// Next encode the SFR message into an empty bytes buffer.
var b bytes.Buffer
if err := sfr.Encode(&b, 0); err != nil {
t.Fatalf("unable to encode SingleFundingResponse: %v", err)
}
// Deserialize the encoded SFR message into a new empty struct.
sfr2 := &SingleFundingResponse{}
if err := sfr2.Decode(&b, 0); err != nil {
t.Fatalf("unable to decode SingleFundingResponse: %v", err)
}
// Assert equality of the two instances.
if !reflect.DeepEqual(sfr, sfr2) {
t.Fatalf("encode/decode error messages don't match %#v vs %#v",
sfr, sfr2)
}
}

View File

@ -1,39 +0,0 @@
package lnwire
import (
"bytes"
"math/big"
"reflect"
"testing"
"github.com/roasbeef/btcd/btcec"
)
func TestSingleFundingSignCompleteWire(t *testing.T) {
// First create a new SFSC message.
sfsc := NewSingleFundingSignComplete(
revHash,
&btcec.Signature{
R: new(big.Int).SetInt64(9),
S: new(big.Int).SetInt64(11),
},
)
// Next encode the SFSC message into an empty bytes buffer.
var b bytes.Buffer
if err := sfsc.Encode(&b, 0); err != nil {
t.Fatalf("unable to encode SingleFundingSignComplete: %v", err)
}
// Deserialize the encoded SFSC message into a new empty struct.
sfsc2 := &SingleFundingSignComplete{}
if err := sfsc2.Decode(&b, 0); err != nil {
t.Fatalf("unable to decode SingleFundingSignComplete: %v", err)
}
// Assert equality of the two instances.
if !reflect.DeepEqual(sfsc, sfsc2) {
t.Fatalf("encode/decode error messages don't match %#v vs %#v",
sfsc, sfsc2)
}
}

View File

@ -1,39 +0,0 @@
package lnwire
import (
"bytes"
"reflect"
"testing"
"github.com/roasbeef/btcutil"
)
func TestUpdateAddHTLCEncodeDecode(t *testing.T) {
// First create a new UPAH message.
addReq := &UpdateAddHTLC{
ChanID: ChannelID(revHash),
ID: 99,
Expiry: uint32(144),
Amount: btcutil.Amount(123456000),
PaymentHash: revHash,
}
copy(addReq.OnionBlob[:], bytes.Repeat([]byte{23}, OnionPacketSize))
// Next encode the HTLCAR message into an empty bytes buffer.
var b bytes.Buffer
if err := addReq.Encode(&b, 0); err != nil {
t.Fatalf("unable to encode HTLCAddRequest: %v", err)
}
// Deserialize the encoded UPAH message into a new empty struct.
addReq2 := &UpdateAddHTLC{}
if err := addReq2.Decode(&b, 0); err != nil {
t.Fatalf("unable to decode HTLCAddRequest: %v", err)
}
// Assert equality of the two instances.
if !reflect.DeepEqual(addReq, addReq2) {
t.Fatalf("encode/decode error messages don't match %#v vs %#v",
addReq, addReq2)
}
}

View File

@ -1,34 +0,0 @@
package lnwire
import (
"bytes"
"reflect"
"testing"
)
func TestUpdateFailHTLC(t *testing.T) {
// First create a new UFH message.
cancelMsg := &UpdateFailHTLC{
ChanID: ChannelID(revHash),
ID: 22,
}
cancelMsg.Reason = []byte{byte(UnknownDestination)}
// Next encode the UFH message into an empty bytes buffer.
var b bytes.Buffer
if err := cancelMsg.Encode(&b, 0); err != nil {
t.Fatalf("unable to encode CancelHTLC: %v", err)
}
// Deserialize the encoded UFH message into a new empty struct.
cancelMsg2 := &UpdateFailHTLC{}
if err := cancelMsg2.Decode(&b, 0); err != nil {
t.Fatalf("unable to decode CancelHTLC: %v", err)
}
// Assert equality of the two instances.
if !reflect.DeepEqual(cancelMsg, cancelMsg2) {
t.Fatalf("encode/decode error messages don't match %#v vs %#v",
cancelMsg, cancelMsg2)
}
}

View File

@ -1,30 +0,0 @@
package lnwire
import (
"bytes"
"reflect"
"testing"
)
func TestUpdateFufillHTLCEncodeDecode(t *testing.T) {
// First create a new HTLCSR message.
settleReq := NewUpdateFufillHTLC(ChannelID(revHash), 23, revHash)
// Next encode the HTLCSR message into an empty bytes buffer.
var b bytes.Buffer
if err := settleReq.Encode(&b, 0); err != nil {
t.Fatalf("unable to encode UpdateFufillHTLC: %v", err)
}
// Deserialize the encoded SFOP message into a new empty struct.
settleReq2 := &UpdateFufillHTLC{}
if err := settleReq2.Decode(&b, 0); err != nil {
t.Fatalf("unable to decode UpdateFufillHTLC: %v", err)
}
// Assert equality of the two instances.
if !reflect.DeepEqual(settleReq, settleReq2) {
t.Fatalf("encode/decode error messages don't match %#v vs %#v",
settleReq, settleReq2)
}
}