func TestCullInvalidConnections(t *testing.T) { d := newDefaultDaemon() // Is fine d.ExpectingIntroductions[addr] = time.Now() // Is expired d.ExpectingIntroductions[addrb] = util.ZeroTime() // Is not in pool d.ExpectingIntroductions[addrc] = util.ZeroTime() d.Peers.Peers.AddPeer(addr) d.Peers.Peers.AddPeer(addrb) d.Peers.Peers.AddPeer(addrc) d.Pool.Pool.Addresses[addr] = gnetConnection(addr) d.Pool.Pool.Addresses[addrb] = gnetConnection(addrb) d.Pool.Pool.Addresses[addrb].Id = 2 d.Pool.Pool.Pool[1] = d.Pool.Pool.Addresses[addr] d.Pool.Pool.Pool[2] = d.Pool.Pool.Addresses[addrb] assert.NotPanics(t, d.cullInvalidConnections) assert.Equal(t, len(d.ExpectingIntroductions), 1) assert.Equal(t, len(d.Peers.Peers.Peerlist), 2) assert.Equal(t, len(d.Pool.Pool.DisconnectQueue), 1) if len(d.Pool.Pool.DisconnectQueue) == 0 { t.Fatal("pool.Pool.DisconnectQueue not empty, would block") } de := <-d.Pool.Pool.DisconnectQueue assert.Equal(t, de.ConnId, 2) assert.Equal(t, de.Reason, DisconnectIntroductionTimeout) shutdown(d) }
func gnetConnection(addr string) *gnet.Connection { return &gnet.Connection{ Id: 1, Conn: NewDummyConn(addr), LastSent: util.ZeroTime(), LastReceived: util.ZeroTime(), Buffer: &bytes.Buffer{}, WriteQueue: make(chan gnet.Message, 16), } }
// Creates an unconfirmed transaction func (self *UnconfirmedTxnPool) createUnconfirmedTxn(bcUnsp *coin.UnspentPool, t coin.Transaction, addrs map[coin.Address]byte) UnconfirmedTxn { now := util.Now() ut := UnconfirmedTxn{ Txn: t, Received: now, Checked: now, Announced: util.ZeroTime(), IsOurReceive: false, IsOurSpend: false, } // Check if this unspent is related to us if addrs != nil { // Check if this is one of our receiving txns for i, _ := range t.Out { if _, ok := addrs[t.Out[i].Address]; ok { ut.IsOurReceive = true break } } // Check if this is one of our spending txns for i, _ := range t.In { if ux, ok := bcUnsp.Get(t.In[i]); ok { if _, ok := addrs[ux.Body.Address]; ok { ut.IsOurSpend = true break } } } } return ut }
func TestGetPeersMessage(t *testing.T) { d := newDefaultDaemon() defer shutdown(d) p := d.Pool m := NewGetPeersMessage() testSimpleMessageHandler(t, d, m) d.Peers.Peers.AddPeer(addr) q, err := d.Peers.Peers.AddPeer(addrb) assert.Nil(t, err) q.Private = true d.Peers.Config.ReplyCount = 100 m.c = messageContext(addr) // Peers disabled d.Peers.Config.Disabled = true assert.NotPanics(t, func() { m.Process(d) }) wait() assert.Equal(t, len(p.Pool.SendResults), 0) assert.True(t, m.c.Conn.LastSent.IsZero()) // Peers enabled d.Peers.Config.Disabled = false m.c = messageContext(addr) defer m.c.Conn.Close() go p.Pool.ConnectionWriteLoop(m.c.Conn) assert.NotPanics(t, func() { m.Process(d) }) wait() assert.Equal(t, len(p.Pool.SendResults), 1) if len(p.Pool.SendResults) == 0 { t.Fatal("SendResults empty, would block") } sr := <-p.Pool.SendResults assert.Nil(t, sr.Error) assert.Equal(t, sr.Connection, m.c.Conn) msg, ok := sr.Message.(*GivePeersMessage) assert.True(t, ok) // Private peer should not be included ipAddr, err := NewIPAddr(addr) assert.Nil(t, err) assert.Equal(t, msg.Peers, []IPAddr{ipAddr}) assert.False(t, m.c.Conn.LastSent.IsZero()) // If no peers, nothing should happen m.c.Conn.LastSent = util.ZeroTime() delete(d.Peers.Peers.Peerlist, addr) assert.NotPanics(t, func() { m.Process(d) }) wait() assert.Equal(t, len(p.Pool.SendResults), 0) assert.True(t, m.c.Conn.LastSent.IsZero()) // Test serialization m = NewGetPeersMessage() b := encoder.Serialize(m) m2 := GetPeersMessage{} assert.Nil(t, encoder.DeserializeRaw(b, &m2)) assert.Equal(t, *m, m2) gnet.EraseMessages() }
func createUnconfirmedTxn() UnconfirmedTxn { ut := UnconfirmedTxn{} ut.Txn = coin.Transaction{} ut.Txn.Head.Hash = randSHA256() ut.Received = util.Now() ut.Checked = ut.Received ut.Announced = util.ZeroTime() return ut }
// Creates an unconfirmed transaction func (utp *UnconfirmedTxnPool) createUnconfirmedTxn(bcUnsp *coin.UnspentPool, t coin.Transaction) UnconfirmedTxn { now := util.Now() return UnconfirmedTxn{ Txn: t, Received: now, Checked: now, Announced: util.ZeroTime(), } }
func testDaemonLoopClearOldPeersTicker(t *testing.T, d *Daemon, quit chan int, count int) { p := pex.NewPeer(addr) p.LastSeen = util.ZeroTime() d.Peers.Peers.Peerlist[addr] = p d.Peers.Config.CullRate = time.Millisecond * 10 go d.Start(quit) time.Sleep(time.Millisecond * 15) assert.Equal(t, len(d.Peers.Peers.Peerlist), count) }
func testDaemonLoopClearStaleConnectionsTicker(t *testing.T, d *Daemon, quit chan int, poolCount int) { c := gnetConnection(addr) c.LastReceived = util.ZeroTime() d.Pool.Pool.Pool[c.Id] = c d.Pool.Config.ClearStaleRate = time.Millisecond * 10 go d.Start(quit) time.Sleep(time.Millisecond * 15) assert.Equal(t, len(d.Pool.Pool.Pool), poolCount) }
// Creates an unconfirmed transaction func (self *UnconfirmedTxnPool) createUnconfirmedTxn(bcUnsp *coin.UnspentPool, t coin.Transaction, addrs map[coin.Address]byte) UnconfirmedTxn { now := util.Now() return UnconfirmedTxn{ Txn: t, Received: now, Checked: now, Announced: util.ZeroTime(), } }
func createUnconfirmedTxn() visor.UnconfirmedTxn { now := util.Now() return visor.UnconfirmedTxn{ Txn: coin.Transaction{ Head: coin.TransactionHeader{ Hash: coin.SumSHA256([]byte("cascas")), }, }, Received: now, Checked: now, Announced: util.ZeroTime(), } }
func TestAnnounceTxnsMessageProcess(t *testing.T) { v, _ := setupVisor() d, _ := newVisorDaemon(v) defer shutdown(d) gc := setupExistingPool(d.Pool) go d.Pool.Pool.ConnectionWriteLoop(gc) tx := createUnconfirmedTxn() txns := []coin.SHA256{tx.Txn.Hash()} m := NewAnnounceTxnsMessage(txns) m.c = messageContext(addr) go d.Pool.Pool.ConnectionWriteLoop(m.c.Conn) defer m.c.Conn.Close() // Disabled, nothing should happen d.Visor.Config.Disabled = true assert.NotPanics(t, func() { m.Process(d) }) wait() assert.Equal(t, len(d.Pool.Pool.SendResults), 0) assert.True(t, m.c.Conn.LastSent.IsZero()) assert.True(t, gc.LastSent.IsZero()) // We don't know some, request them d.Visor.Config.Disabled = false assert.NotPanics(t, func() { m.Process(d) }) wait() assert.Equal(t, len(d.Pool.Pool.SendResults), 1) if len(d.Pool.Pool.SendResults) == 0 { t.Fatal("SendResults empty, would block") } sr := <-d.Pool.Pool.SendResults assert.Equal(t, sr.Connection, m.c.Conn) assert.Nil(t, sr.Error) _, ok := sr.Message.(*GetTxnsMessage) assert.True(t, ok) assert.False(t, m.c.Conn.LastSent.IsZero()) // Should not have been broadcast assert.True(t, gc.LastSent.IsZero()) // We know all the reported txns, nothing should be sent d.Visor.Visor.Unconfirmed.Txns[tx.Txn.Hash()] = tx m.c.Conn.Conn = NewDummyConn(addr) m.c.Conn.LastSent = util.ZeroTime() assert.NotPanics(t, func() { m.Process(d) }) wait() assert.Equal(t, len(d.Pool.Pool.SendResults), 0) assert.True(t, m.c.Conn.LastSent.IsZero()) assert.True(t, gc.LastSent.IsZero()) }
func TestVisorRequestBlocksFromAddr(t *testing.T) { defer cleanupVisor() defer gnet.EraseMessages() p, gc := setupPool() vc, _ := setupVisor() go p.Pool.ConnectionWriteLoop(gc) // Disabled vc.Disabled = true v := NewVisor(vc) assert.NotPanics(t, func() { err := v.RequestBlocksFromAddr(p, addr) assert.NotNil(t, err) assert.Equal(t, err.Error(), "Visor disabled") }) wait() assert.Equal(t, len(p.Pool.SendResults), 0) assert.True(t, gc.LastSent.IsZero()) vc.Disabled = false v = NewVisor(vc) assert.NotPanics(t, func() { assert.Nil(t, v.RequestBlocksFromAddr(p, addr)) }) wait() assert.Equal(t, len(p.Pool.SendResults), 1) if len(p.Pool.SendResults) == 0 { t.Fatal("SendResults empty, would block") } sr := <-p.Pool.SendResults assert.Nil(t, sr.Error) assert.Equal(t, sr.Connection, gc) _, ok := sr.Message.(*GetBlocksMessage) assert.True(t, ok) assert.False(t, gc.LastSent.IsZero()) // No connection found for addr gc.LastSent = util.ZeroTime() gc.Conn = NewDummyConn(addr) delete(p.Pool.Pool, gc.Id) delete(p.Pool.Addresses, gc.Addr()) assert.NotPanics(t, func() { assert.NotNil(t, v.RequestBlocksFromAddr(p, addr)) }) wait() assert.Equal(t, len(p.Pool.SendResults), 0) assert.True(t, gc.LastSent.IsZero()) }
func testDaemonLoopPingCheckTicker(t *testing.T, d *Daemon, quit chan int, sent bool) { c := gnetConnection(addr) go d.Pool.Pool.ConnectionWriteLoop(c) c.LastSent = util.ZeroTime() d.Pool.Pool.Pool[c.Id] = c d.Pool.Config.IdleCheckRate = time.Millisecond * 10 go d.Start(quit) time.Sleep(time.Millisecond * 15) if sent { assert.False(t, c.LastSent.IsZero()) } else { assert.True(t, c.LastSent.IsZero()) } c.Close() wait() }
func TestClearStaleConnections(t *testing.T) { dm := newDefaultDaemon() defer shutdown(dm) c := gnetConnection(addr) d := gnetConnection(addrb) c.LastReceived = util.ZeroTime() d.LastReceived = time.Now() dm.Pool.Pool.Pool[1] = c dm.Pool.Pool.Pool[2] = d assert.NotPanics(t, dm.Pool.clearStaleConnections) assert.Equal(t, len(dm.Pool.Pool.DisconnectQueue), 1) if len(dm.Pool.Pool.DisconnectQueue) == 0 { t.Fatalf("Empty DisconnectQueue, would block") } de := <-dm.Pool.Pool.DisconnectQueue assert.Equal(t, de.ConnId, 1) assert.Equal(t, de.Reason, DisconnectIdle) }
func TestOnConnect(t *testing.T) { d := newDefaultDaemon() // Test a valid connection, unsolicited e := ConnectEvent{addr, false} p, _ := d.Peers.Peers.AddPeer(addr) c := setupExistingPool(d.Pool) go d.Pool.Pool.ConnectionWriteLoop(c) d.pendingConnections[addr] = p assert.NotPanics(t, func() { d.onConnect(e) }) wait() assert.Equal(t, len(d.Pool.Pool.SendResults), 1) if len(d.Pool.Pool.SendResults) == 0 { t.Fatalf("SendResults empty, would block") } sr := <-d.Pool.Pool.SendResults assert.Equal(t, sr.Connection, c) assert.Nil(t, sr.Error) _, ok := sr.Message.(*IntroductionMessage) assert.True(t, ok) // This connection should no longer be pending assert.Equal(t, len(d.pendingConnections), 0) // This is not an outgoing connection, we did not solicit it assert.Equal(t, len(d.OutgoingConnections), 0) // We should be expecting its version assert.Equal(t, len(d.ExpectingIntroductions), 1) _, exists := d.ExpectingIntroductions[addr] assert.True(t, exists) // An introduction should have been sent assert.False(t, c.LastSent.IsZero()) // d.ipCounts should be 1 assert.Equal(t, d.ipCounts[addrIP], 1) // Cleanup delete(d.ipCounts, addrIP) delete(d.ExpectingIntroductions, addr) c.Close() // Test a valid connection, solicited e = ConnectEvent{addr, true} c = gnetConnection(addr) go d.Pool.Pool.ConnectionWriteLoop(c) d.pendingConnections[addr] = p d.Pool.Pool.Addresses[addr] = c d.Pool.Pool.Pool[c.Id] = c assert.NotPanics(t, func() { d.onConnect(e) }) wait() assert.Equal(t, len(d.Pool.Pool.SendResults), 1) if len(d.Pool.Pool.SendResults) == 0 { t.Fatalf("SendResults empty, would block") } sr = <-d.Pool.Pool.SendResults assert.Equal(t, sr.Connection, c) assert.Nil(t, sr.Error) _, ok = sr.Message.(*IntroductionMessage) assert.True(t, ok) // This connection should no longer be pending assert.Equal(t, len(d.pendingConnections), 0) // We should mark this as an outgoing connection since we solicited it assert.Equal(t, len(d.OutgoingConnections), 1) assert.NotNil(t, d.OutgoingConnections[addr]) // We should be expecting its version assert.Equal(t, len(d.ExpectingIntroductions), 1) _, exists = d.ExpectingIntroductions[addr] assert.True(t, exists) // An introduction should have been sent assert.False(t, c.LastSent.IsZero()) // d.ipCounts should be 1 assert.Equal(t, d.ipCounts[addrIP], 1) // Cleanup c.Close() delete(d.ExpectingIntroductions, addr) delete(d.OutgoingConnections, addr) delete(d.ipCounts, addrIP) // Test a connection that is not connected by the time of processing c.LastSent = util.ZeroTime() e = ConnectEvent{addr, true} delete(d.Pool.Pool.Addresses, addr) d.pendingConnections[addr] = p assert.NotPanics(t, func() { d.onConnect(e) }) wait() assert.Equal(t, len(d.Pool.Pool.SendResults), 0) // This connection should no longer be pending assert.Equal(t, len(d.pendingConnections), 0) // No message should have been sent assert.True(t, c.LastSent.IsZero()) // We should not be expecting its version assert.Equal(t, len(d.ExpectingIntroductions), 0) // We should not have recorded it to ipCount assert.Equal(t, d.ipCounts[addrIP], 0) // Test a connection that is blacklisted e = ConnectEvent{addr, true} c = gnetConnection(addr) go d.Pool.Pool.ConnectionWriteLoop(c) d.Peers.Peers.AddBlacklistEntry(addr, time.Hour) d.pendingConnections[addr] = p d.Pool.Pool.Addresses[addr] = c d.Pool.Pool.Pool[c.Id] = c assert.NotPanics(t, func() { d.onConnect(e) }) wait() // No introduction should have been sent assert.Equal(t, len(d.Pool.Pool.SendResults), 0) // This connection should no longer be pending assert.Equal(t, len(d.pendingConnections), 0) // No message should have been sent assert.True(t, c.LastSent.IsZero()) // We should not be expecting its version assert.Equal(t, len(d.ExpectingIntroductions), 0) // We should not have recorded its ipCount assert.Equal(t, d.ipCounts[addrIP], 0) // We should be looking to disconnect this client assert.Equal(t, len(d.Pool.Pool.DisconnectQueue), 1) if len(d.Pool.Pool.DisconnectQueue) == 0 { t.Fatal("pool.Pool.DisconnectQueue is empty, would block") } de := <-d.Pool.Pool.DisconnectQueue assert.Equal(t, de.ConnId, 1) assert.Equal(t, de.Reason, DisconnectIsBlacklisted) // Cleanup c.Close() delete(d.Peers.Peers.Blacklist, addr) // Test a connection that has reached maxed ipCount e = ConnectEvent{addr, true} c = gnetConnection(addr) go d.Pool.Pool.ConnectionWriteLoop(c) d.ipCounts[addrIP] = d.Config.IPCountsMax d.pendingConnections[addr] = p d.Pool.Pool.Addresses[addr] = c d.Pool.Pool.Pool[c.Id] = c assert.NotPanics(t, func() { d.onConnect(e) }) wait() // No introduction should have been sent assert.Equal(t, len(d.Pool.Pool.SendResults), 0) // This connection should no longer be pending assert.Equal(t, len(d.pendingConnections), 0) // No message should have been sent assert.True(t, c.LastSent.IsZero()) // We should not be expecting its version assert.Equal(t, len(d.ExpectingIntroductions), 0) // d.ipCounts should be unchanged assert.Equal(t, d.ipCounts[addrIP], d.Config.IPCountsMax) // We should be looking to disconnect this client assert.Equal(t, len(d.Pool.Pool.DisconnectQueue), 1) if len(d.Pool.Pool.DisconnectQueue) == 0 { t.Fatal("pool.Pool.DisconnectQueue is empty, would block") } de = <-d.Pool.Pool.DisconnectQueue assert.Equal(t, de.ConnId, 1) assert.Equal(t, de.Reason, DisconnectIPLimitReached) // Cleanup c.Close() delete(d.ipCounts, addrIP) gnet.EraseMessages() shutdown(d) }
func TestRecordTxn(t *testing.T) { defer cleanupVisor() // Test with invalid txn mv := setupMasterVisor() ut := NewUnconfirmedTxnPool() txn, err := makeInvalidTxn(mv) assert.Nil(t, err) err, known := ut.RecordTxn(mv.blockchain, txn, nil, testBlockSize, 0) assert.NotNil(t, err) assert.False(t, known) assert.Equal(t, len(ut.Txns), 0) // Test didAnnounce=false mv = setupMasterVisor() ut = NewUnconfirmedTxnPool() txn, err = makeValidTxn(mv) assert.Nil(t, err) err, known = ut.RecordTxn(mv.blockchain, txn, nil, testBlockSize, 0) assert.Nil(t, err) assert.False(t, known) assertValidUnspent(t, mv.blockchain, ut.Unspent, txn) assertValidUnconfirmed(t, ut.Txns, txn) // Test didAnnounce=true mv = setupMasterVisor() ut = NewUnconfirmedTxnPool() txn, err = makeValidTxn(mv) assert.Nil(t, err) err, known = ut.RecordTxn(mv.blockchain, txn, nil, testBlockSize, 0) assert.Nil(t, err) assert.False(t, known) assertValidUnspent(t, mv.blockchain, ut.Unspent, txn) assertValidUnconfirmed(t, ut.Txns, txn) // Test txn too large mv = setupMasterVisor() ut = NewUnconfirmedTxnPool() txn, err = makeValidTxn(mv) assert.Nil(t, err) err, known = ut.RecordTxn(mv.blockchain, txn, nil, txn.Size()-1, 1) assertError(t, err, "Transaction too large") assert.False(t, known) assert.Equal(t, len(ut.Txns), 0) // Test where we are receiver of ux outputs mv = setupMasterVisor() assert.Equal(t, len(mv.blockchain.Unspent.Pool), 1) ut = NewUnconfirmedTxnPool() txn, err = makeValidTxn(mv) assert.Nil(t, err) addrs := make(map[cipher.Address]byte, 1) addrs[txn.Out[1].Address] = byte(1) err, known = ut.RecordTxn(mv.blockchain, txn, addrs, testBlockSize, 0) assert.Nil(t, err) assert.False(t, known) assertValidUnspent(t, mv.blockchain, ut.Unspent, txn) assertValidUnconfirmed(t, ut.Txns, txn) // Test where we are spender of ux outputs mv = setupMasterVisor() assert.Equal(t, len(mv.blockchain.Unspent.Pool), 1) ut = NewUnconfirmedTxnPool() txn, err = makeValidTxnNoChange(mv) assert.Nil(t, err) addrs = make(map[cipher.Address]byte, 1) ux, ok := mv.blockchain.Unspent.Get(txn.In[0]) assert.True(t, ok) addrs[ux.Body.Address] = byte(1) err, known = ut.RecordTxn(mv.blockchain, txn, addrs, testBlockSize, 0) assert.Nil(t, err) assert.False(t, known) assertValidUnspent(t, mv.blockchain, ut.Unspent, txn) assertValidUnconfirmed(t, ut.Txns, txn) // Test where we are both spender and receiver of ux outputs mv = setupMasterVisor() ut = NewUnconfirmedTxnPool() txn, err = makeValidTxn(mv) assert.Nil(t, err) addrs = make(map[cipher.Address]byte, 2) addrs[txn.Out[0].Address] = byte(1) ux, ok = mv.blockchain.Unspent.Get(txn.In[0]) assert.True(t, ok) addrs[ux.Body.Address] = byte(1) err, known = ut.RecordTxn(mv.blockchain, txn, addrs, testBlockSize, 0) assert.Nil(t, err) assert.False(t, known) assertValidUnspent(t, mv.blockchain, ut.Unspent, txn) assertValidUnconfirmed(t, ut.Txns, txn) assert.Equal(t, len(ut.Txns), 1) assert.Equal(t, len(ut.Unspent), 1) for _, uxs := range ut.Unspent { assert.Equal(t, len(uxs), 2) } // Test duplicate Record, should be no-op besides state change utx := ut.Txns[txn.Hash()] // Set a placeholder value on the utx to check if we overwrote it utx.Announced = util.ZeroTime().Add(time.Minute) ut.Txns[txn.Hash()] = utx err, known = ut.RecordTxn(mv.blockchain, txn, addrs, testBlockSize, 0) assert.Nil(t, err) assert.True(t, known) utx2 := ut.Txns[txn.Hash()] assert.Equal(t, utx2.Announced, util.ZeroTime().Add(time.Minute)) utx2.Announced = util.ZeroTime() ut.Txns[utx2.Hash()] = utx2 // Received & checked should be updated assert.True(t, utx2.Received.After(utx.Received)) assert.True(t, utx2.Checked.After(utx.Checked)) assertValidUnconfirmed(t, ut.Txns, txn) assert.Equal(t, len(ut.Txns), 1) assert.Equal(t, len(ut.Unspent), 1) for _, uxs := range ut.Unspent { assert.Equal(t, len(uxs), 2) } // Test with valid fee, exact mv = setupMasterVisor() assert.Equal(t, len(mv.blockchain.Unspent.Pool), 1) ut = NewUnconfirmedTxnPool() txn, err = makeValidTxnWithFeeFactor(mv, 4, 0) assert.Nil(t, err) addrs = make(map[cipher.Address]byte, 1) addrs[txn.Out[1].Address] = byte(1) err, known = ut.RecordTxn(mv.blockchain, txn, addrs, testBlockSize, 4) assert.Nil(t, err) assert.False(t, known) assertValidUnspent(t, mv.blockchain, ut.Unspent, txn) assertValidUnconfirmed(t, ut.Txns, txn) // Test with valid fee, surplus mv = setupMasterVisor() assert.Equal(t, len(mv.blockchain.Unspent.Pool), 1) ut = NewUnconfirmedTxnPool() txn, err = makeValidTxnWithFeeFactor(mv, 4, 100) assert.Nil(t, err) addrs = make(map[cipher.Address]byte, 1) addrs[txn.Out[1].Address] = byte(1) err, known = ut.RecordTxn(mv.blockchain, txn, addrs, testBlockSize, 4) assert.Nil(t, err) assert.False(t, known) assertValidUnspent(t, mv.blockchain, ut.Unspent, txn) assertValidUnconfirmed(t, ut.Txns, txn) // Test with invalid fee mv = setupMasterVisor() assert.Equal(t, len(mv.blockchain.Unspent.Pool), 1) ut = NewUnconfirmedTxnPool() txn, err = makeValidTxnWithFeeFactor(mv, 5, 0) assert.Nil(t, err) _, err = mv.blockchain.TransactionFee(&txn) assert.Nil(t, err) addrs = make(map[cipher.Address]byte, 1) addrs[txn.Out[1].Address] = byte(1) err, known = ut.RecordTxn(mv.blockchain, txn, addrs, testBlockSize, 4) assertError(t, err, "Transaction fee minimum not met") assert.False(t, known) assert.Equal(t, len(ut.Txns), 0) // Test with bc.TransactionFee failing mv = setupMasterVisor() assert.Equal(t, len(mv.blockchain.Unspent.Pool), 1) ut = NewUnconfirmedTxnPool() txn, err = makeValidTxnWithFeeFactor(mv, 4, 100) assert.Nil(t, err) txn.Out[1].Hours = 1e16 txn.Head.Sigs = make([]cipher.Sig, 0) txn.SignInputs([]cipher.SecKey{mv.Config.MasterKeys.Secret}) txn.UpdateHeader() addrs = make(map[cipher.Address]byte, 1) addrs[txn.Out[1].Address] = byte(1) err, known = ut.RecordTxn(mv.blockchain, txn, addrs, testBlockSize, 4) assertError(t, err, "Insufficient coinhours for transaction outputs") assert.False(t, known) assert.Equal(t, len(ut.Txns), 0) }
func testRefresh(t *testing.T, mv *Visor, refresh func(checkPeriod, maxAge time.Duration)) { up := mv.Unconfirmed // Add a transaction that is invalid, but will not be checked yet // Add a transaction that is invalid, and will be checked and removed invalidTxUnchecked, err := makeValidTxn(mv) assert.Nil(t, err) invalidTxChecked, err := makeValidTxn(mv) assert.Nil(t, err) assert.Nil(t, invalidTxUnchecked.Verify()) assert.Nil(t, invalidTxChecked.Verify()) // Invalidate it by spending the output that this txn references invalidator, err := makeValidTxn(mv) assert.Nil(t, err) assert.Nil(t, up.InjectTxn(mv.blockchain, invalidator, nil, false)) assert.Equal(t, len(up.Txns), 1) _, err = mv.CreateAndExecuteBlock() assert.Nil(t, err) assert.Equal(t, len(up.Txns), 0) assert.NotNil(t, mv.blockchain.VerifyTransaction(invalidTxUnchecked)) assert.NotNil(t, mv.blockchain.VerifyTransaction(invalidTxChecked)) invalidUtxUnchecked := UnconfirmedTxn{ Txn: invalidTxUnchecked, Received: util.Now(), Checked: util.Now(), Announced: util.ZeroTime(), } invalidUtxChecked := invalidUtxUnchecked invalidUtxChecked.Txn = invalidTxChecked invalidUtxUnchecked.Checked = util.Now().Add(time.Hour) invalidUtxChecked.Checked = util.Now().Add(-time.Hour) up.Txns[invalidUtxUnchecked.Hash()] = invalidUtxUnchecked up.Txns[invalidUtxChecked.Hash()] = invalidUtxChecked assert.Equal(t, len(up.Txns), 2) bh := coin.BlockHeader{} for _, ux := range mv.blockchain.TxUxOut(invalidTxUnchecked, bh) { up.Unspent.Add(ux) } for _, ux := range mv.blockchain.TxUxOut(invalidTxChecked, bh) { up.Unspent.Add(ux) } // Add a transaction that is valid, and will not be checked yet validTxUnchecked, err := makeValidTxn(mv) assert.Nil(t, err) assert.Nil(t, up.InjectTxn(mv.blockchain, validTxUnchecked, nil, false)) assert.Equal(t, len(up.Txns), 3) validUtxUnchecked := up.Txns[validTxUnchecked.Hash()] validUtxUnchecked.Checked = util.Now().Add(time.Hour) up.Txns[validUtxUnchecked.Hash()] = validUtxUnchecked // Add a transaction that is valid, and will be checked validTxChecked, err := makeValidTxn(mv) assert.Nil(t, err) assert.Nil(t, up.InjectTxn(mv.blockchain, validTxChecked, nil, false)) assert.Equal(t, len(up.Txns), 4) validUtxChecked := up.Txns[validTxChecked.Hash()] validUtxChecked.Checked = util.Now().Add(-time.Hour) up.Txns[validUtxChecked.Hash()] = validUtxChecked // Add a transaction that is expired validTxExpired, err := makeValidTxn(mv) assert.Nil(t, err) assert.Nil(t, up.InjectTxn(mv.blockchain, validTxExpired, nil, false)) assert.Equal(t, len(up.Txns), 5) validUtxExpired := up.Txns[validTxExpired.Hash()] validUtxExpired.Received = util.Now().Add(-time.Hour) up.Txns[validTxExpired.Hash()] = validUtxExpired // Pre-sanity check assert.Equal(t, len(up.Unspent.Arr), 2*5) assert.Equal(t, len(up.Txns), 5) // Refresh checkPeriod := time.Second * 2 maxAge := time.Second * 4 refresh(checkPeriod, maxAge) // All utxns that are unchecked should be exactly the same assert.Equal(t, up.Txns[validUtxUnchecked.Hash()], validUtxUnchecked) assert.Equal(t, up.Txns[invalidUtxUnchecked.Hash()], invalidUtxUnchecked) // The valid one that is checked should have its checked status updated validUtxCheckedUpdated := up.Txns[validUtxChecked.Hash()] assert.True(t, validUtxCheckedUpdated.Checked.After(validUtxChecked.Checked)) validUtxChecked.Checked = validUtxCheckedUpdated.Checked assert.Equal(t, validUtxChecked, validUtxCheckedUpdated) // The invalid checked one and the expired one should be removed _, ok := up.Txns[invalidUtxChecked.Hash()] assert.False(t, ok) _, ok = up.Txns[validUtxExpired.Hash()] assert.False(t, ok) // Also, the unspents should have 2 * nRemaining assert.Equal(t, len(up.Unspent.Arr), 2*3) assert.Equal(t, len(up.Txns), 3) }
func gnetConnection(addr string) *gnet.Connection { c := gnet.NewConnection(nil, 1, NewDummyConn(addr), 16) c.LastSent = util.ZeroTime() c.LastReceived = util.ZeroTime() return c }
func TestGiveBlocksMessageProcess(t *testing.T) { v, mv := setupVisor() d, _ := newVisorDaemon(v) defer shutdown(d) gc := setupExistingPool(d.Pool) go d.Pool.Pool.ConnectionWriteLoop(gc) blocks, err := makeBlocks(mv, 2) assert.Nil(t, err) assert.Equal(t, len(blocks), 2) m := NewGiveBlocksMessage(blocks) m.c = messageContext(addr) // Disabled should have nothing happen d.Visor.Config.Disabled = true m.Process(d) wait() assert.Equal(t, len(d.Pool.Pool.SendResults), 0) assert.Equal(t, d.Visor.Visor.MostRecentBkSeq(), uint64(0)) assert.True(t, gc.LastSent.IsZero()) // Not disabled and blocks were reannounced d.Visor.Config.Disabled = false gc.Conn = NewDummyConn(addr) assert.Equal(t, len(blocks), 2) m = NewGiveBlocksMessage(blocks) assert.Equal(t, len(m.Blocks), 2) m.c = messageContext(addr) m.Process(d) wait() assert.Equal(t, len(d.Pool.Pool.SendResults), 1) if len(d.Pool.Pool.SendResults) == 0 { t.Fatal("SendResults empty, would block") } sr := <-d.Pool.Pool.SendResults assert.Nil(t, sr.Error) assert.Equal(t, sr.Connection, gc) _, ok := sr.Message.(*AnnounceBlocksMessage) assert.True(t, ok) assert.Equal(t, d.Visor.Visor.MostRecentBkSeq(), uint64(2)) assert.False(t, gc.LastSent.IsZero()) // Send blocks we have and some we dont, as long as they are in order // we can use the ones at the end gc.LastSent = util.ZeroTime() moreBlocks, err := makeBlocks(mv, 2) assert.Nil(t, err) blocks = append(blocks, moreBlocks...) m = NewGiveBlocksMessage(blocks) m.c = messageContext(addr) m.Process(d) wait() assert.Equal(t, len(d.Pool.Pool.SendResults), 1) if len(d.Pool.Pool.SendResults) == 0 { t.Fatal("SendResults empty, would block") } sr = <-d.Pool.Pool.SendResults assert.Nil(t, sr.Error) assert.Equal(t, sr.Connection, gc) _, ok = sr.Message.(*AnnounceBlocksMessage) assert.True(t, ok) assert.Equal(t, d.Visor.Visor.MostRecentBkSeq(), uint64(4)) assert.False(t, gc.LastSent.IsZero()) // Send invalid blocks gc.LastSent = util.ZeroTime() bb := visor.SignedBlock{ Block: coin.Block{ Head: coin.BlockHeader{ BkSeq: uint64(7), }}} m = NewGiveBlocksMessage([]visor.SignedBlock{bb}) m.c = messageContext(addr) m.Process(d) assert.Equal(t, len(d.Pool.Pool.SendResults), 0) assert.Equal(t, d.Visor.Visor.MostRecentBkSeq(), uint64(4)) assert.True(t, gc.LastSent.IsZero()) }
func TestVisorResendTransaction(t *testing.T) { defer cleanupVisor() defer gnet.EraseMessages() p, gc := setupPool() go p.Pool.ConnectionWriteLoop(gc) vc, mv := setupVisor() v := NewVisor(vc) assert.Equal(t, len(v.Visor.Unconfirmed.Txns), 0) // Nothing should happen if txn unknown v.ResendTransaction(coin.SumSHA256([]byte("garbage")), p) wait() assert.Equal(t, len(p.Pool.SendResults), 0) assert.Equal(t, len(p.Pool.SendResults), 0) assert.Equal(t, len(v.Visor.Unconfirmed.Txns), 0) assert.True(t, gc.LastSent.IsZero()) // give the visor some coins, and make a spend to add a txn assert.Nil(t, transferCoins(mv, v.Visor)) tx, err := v.Spend(visor.Balance{10e6, 0}, 0, mv.Wallet.GetAddresses()[0], p) assert.Nil(t, err) wait() assert.Equal(t, len(p.Pool.SendResults), 1) if len(p.Pool.SendResults) == 0 { t.Fatal("SendResults empty, would block") } <-p.Pool.SendResults assert.Equal(t, len(v.Visor.Unconfirmed.Txns), 1) h := tx.Hash() ut := v.Visor.Unconfirmed.Txns[h] ut.Announced = util.ZeroTime() v.Visor.Unconfirmed.Txns[h] = ut assert.True(t, v.Visor.Unconfirmed.Txns[h].Announced.IsZero()) // Reset the sent timer since we made a successful spend gc.LastSent = util.ZeroTime() // Nothing should send if disabled v.Config.Disabled = true v.ResendTransaction(h, p) wait() assert.Equal(t, len(p.Pool.SendResults), 0) ann := v.Visor.Unconfirmed.Txns[h].Announced assert.True(t, ann.IsZero()) assert.True(t, gc.LastSent.IsZero()) // Should have resent v.Config.Disabled = false gc.Conn = NewDummyConn(addr) v.ResendTransaction(h, p) wait() assert.Equal(t, len(p.Pool.SendResults), 1) if len(p.Pool.SendResults) == 0 { t.Fatal("SendResults empty, would block") } sr := <-p.Pool.SendResults assert.Nil(t, sr.Error) assert.Equal(t, sr.Connection, gc) _, ok := sr.Message.(*GiveTxnsMessage) assert.True(t, ok) ann = v.Visor.Unconfirmed.Txns[h].Announced // Announced state should not be updated until we process it assert.True(t, ann.IsZero()) assert.False(t, gc.LastSent.IsZero()) }