예제 #1
0
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)
}
예제 #2
0
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),
	}
}
예제 #3
0
파일: unconfirmed.go 프로젝트: up4k/skycoin
// 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
}
예제 #4
0
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()
}
예제 #5
0
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
}
예제 #6
0
// 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(),
	}
}
예제 #7
0
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)
}
예제 #8
0
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)
}
예제 #9
0
// 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(),
	}
}
예제 #10
0
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(),
	}
}
예제 #11
0
파일: visor_test.go 프로젝트: up4k/skycoin
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())
}
예제 #12
0
파일: visor_test.go 프로젝트: up4k/skycoin
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())
}
예제 #13
0
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()
}
예제 #14
0
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)
}
예제 #15
0
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)
}
예제 #16
0
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)
}
예제 #17
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)
}
예제 #18
0
func gnetConnection(addr string) *gnet.Connection {
	c := gnet.NewConnection(nil, 1, NewDummyConn(addr), 16)
	c.LastSent = util.ZeroTime()
	c.LastReceived = util.ZeroTime()
	return c
}
예제 #19
0
파일: visor_test.go 프로젝트: up4k/skycoin
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())
}
예제 #20
0
파일: visor_test.go 프로젝트: up4k/skycoin
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())
}