2016-01-15 06:56:25 +03:00
|
|
|
package uspv
|
|
|
|
|
|
|
|
import (
|
2016-01-29 06:35:49 +03:00
|
|
|
"fmt"
|
2016-01-15 06:56:25 +03:00
|
|
|
"log"
|
|
|
|
|
|
|
|
"github.com/btcsuite/btcd/wire"
|
|
|
|
)
|
|
|
|
|
2016-01-15 10:08:37 +03:00
|
|
|
func (s *SPVCon) incomingMessageHandler() {
|
2016-01-15 06:56:25 +03:00
|
|
|
for {
|
2016-02-03 10:37:29 +03:00
|
|
|
n, xm, _, err := wire.ReadMessageN(s.con, s.localVersion, s.TS.Param.Net)
|
2016-01-15 06:56:25 +03:00
|
|
|
if err != nil {
|
|
|
|
log.Printf("ReadMessageN error. Disconnecting: %s\n", err.Error())
|
|
|
|
return
|
|
|
|
}
|
2016-01-15 10:08:37 +03:00
|
|
|
s.RBytes += uint64(n)
|
2016-01-15 06:56:25 +03:00
|
|
|
// log.Printf("Got %d byte %s message\n", n, xm.Command())
|
|
|
|
switch m := xm.(type) {
|
|
|
|
case *wire.MsgVersion:
|
|
|
|
log.Printf("Got version message. Agent %s, version %d, at height %d\n",
|
|
|
|
m.UserAgent, m.ProtocolVersion, m.LastBlock)
|
2016-01-15 10:08:37 +03:00
|
|
|
s.remoteVersion = uint32(m.ProtocolVersion) // weird cast! bug?
|
2016-01-15 06:56:25 +03:00
|
|
|
case *wire.MsgVerAck:
|
|
|
|
log.Printf("Got verack. Whatever.\n")
|
|
|
|
case *wire.MsgAddr:
|
|
|
|
log.Printf("got %d addresses.\n", len(m.AddrList))
|
|
|
|
case *wire.MsgPing:
|
2016-01-29 06:35:49 +03:00
|
|
|
// log.Printf("Got a ping message. We should pong back or they will kick us off.")
|
2016-01-29 09:31:05 +03:00
|
|
|
go s.PongBack(m.Nonce)
|
2016-01-15 06:56:25 +03:00
|
|
|
case *wire.MsgPong:
|
|
|
|
log.Printf("Got a pong response. OK.\n")
|
2016-02-07 09:48:54 +03:00
|
|
|
case *wire.MsgBlock:
|
|
|
|
s.IngestBlock(m)
|
2016-01-15 06:56:25 +03:00
|
|
|
case *wire.MsgMerkleBlock:
|
2016-02-07 06:15:35 +03:00
|
|
|
s.IngestMerkleBlock(m)
|
2016-01-31 13:08:39 +03:00
|
|
|
case *wire.MsgHeaders: // concurrent because we keep asking for blocks
|
2016-01-29 09:31:05 +03:00
|
|
|
go s.HeaderHandler(m)
|
2016-01-31 13:08:39 +03:00
|
|
|
case *wire.MsgTx: // not concurrent! txs must be in order
|
2016-01-31 12:05:31 +03:00
|
|
|
s.TxHandler(m)
|
2016-01-22 08:50:42 +03:00
|
|
|
case *wire.MsgReject:
|
|
|
|
log.Printf("Rejected! cmd: %s code: %s tx: %s reason: %s",
|
|
|
|
m.Cmd, m.Code.String(), m.Hash.String(), m.Reason)
|
2016-01-23 03:04:27 +03:00
|
|
|
case *wire.MsgInv:
|
2016-02-03 04:14:13 +03:00
|
|
|
s.InvHandler(m)
|
2016-01-27 12:24:16 +03:00
|
|
|
case *wire.MsgNotFound:
|
|
|
|
log.Printf("Got not found response from remote:")
|
2016-01-23 03:04:27 +03:00
|
|
|
for i, thing := range m.InvList {
|
2016-01-27 12:24:16 +03:00
|
|
|
log.Printf("\t$d) %s: %s", i, thing.Type, thing.Hash)
|
2016-01-23 03:04:27 +03:00
|
|
|
}
|
2016-02-05 12:16:45 +03:00
|
|
|
case *wire.MsgGetData:
|
|
|
|
s.GetDataHandler(m)
|
2016-02-07 09:48:54 +03:00
|
|
|
|
2016-01-15 06:56:25 +03:00
|
|
|
default:
|
|
|
|
log.Printf("Got unknown message type %s\n", m.Command())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// this one seems kindof pointless? could get ridf of it and let
|
|
|
|
// functions call WriteMessageN themselves...
|
2016-01-15 10:08:37 +03:00
|
|
|
func (s *SPVCon) outgoingMessageHandler() {
|
2016-01-15 06:56:25 +03:00
|
|
|
for {
|
2016-01-15 10:08:37 +03:00
|
|
|
msg := <-s.outMsgQueue
|
2016-02-03 10:37:29 +03:00
|
|
|
n, err := wire.WriteMessageN(s.con, msg, s.localVersion, s.TS.Param.Net)
|
2016-01-15 06:56:25 +03:00
|
|
|
if err != nil {
|
|
|
|
log.Printf("Write message error: %s", err.Error())
|
|
|
|
}
|
2016-01-15 10:08:37 +03:00
|
|
|
s.WBytes += uint64(n)
|
2016-01-15 06:56:25 +03:00
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
2016-01-27 12:24:16 +03:00
|
|
|
|
2016-01-29 06:35:49 +03:00
|
|
|
// fPositiveHandler monitors false positives and when it gets enough of them,
|
|
|
|
//
|
|
|
|
func (s *SPVCon) fPositiveHandler() {
|
|
|
|
var fpAccumulator int32
|
|
|
|
for {
|
|
|
|
fpAccumulator += <-s.fPositives // blocks here
|
|
|
|
if fpAccumulator > 7 {
|
|
|
|
filt, err := s.TS.GimmeFilter()
|
|
|
|
if err != nil {
|
|
|
|
log.Printf("Filter creation error: %s\n", err.Error())
|
|
|
|
log.Printf("uhoh, crashing filter handler")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
// send filter
|
|
|
|
s.SendFilter(filt)
|
|
|
|
fmt.Printf("sent filter %x\n", filt.MsgFilterLoad().Filter)
|
2016-02-16 09:13:17 +03:00
|
|
|
|
2016-01-29 06:35:49 +03:00
|
|
|
// clear the channel
|
2016-02-16 09:13:17 +03:00
|
|
|
finClear:
|
|
|
|
for {
|
|
|
|
select {
|
|
|
|
case x := <-s.fPositives:
|
|
|
|
fpAccumulator += x
|
|
|
|
default:
|
|
|
|
break finClear
|
|
|
|
}
|
2016-01-29 06:35:49 +03:00
|
|
|
}
|
2016-02-16 09:13:17 +03:00
|
|
|
|
2016-01-29 06:35:49 +03:00
|
|
|
fmt.Printf("reset %d false positives\n", fpAccumulator)
|
|
|
|
// reset accumulator
|
|
|
|
fpAccumulator = 0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-01-29 09:31:05 +03:00
|
|
|
func (s *SPVCon) HeaderHandler(m *wire.MsgHeaders) {
|
|
|
|
moar, err := s.IngestHeaders(m)
|
|
|
|
if err != nil {
|
|
|
|
log.Printf("Header error: %s\n", err.Error())
|
|
|
|
return
|
|
|
|
}
|
2016-02-04 07:26:12 +03:00
|
|
|
// more to get? if so, ask for them and return
|
2016-01-29 09:31:05 +03:00
|
|
|
if moar {
|
2016-02-04 07:26:12 +03:00
|
|
|
err = s.AskForHeaders()
|
2016-01-31 13:08:39 +03:00
|
|
|
if err != nil {
|
2016-02-04 07:26:12 +03:00
|
|
|
log.Printf("AskForHeaders error: %s", err.Error())
|
2016-01-31 13:08:39 +03:00
|
|
|
}
|
2016-02-04 07:26:12 +03:00
|
|
|
return
|
|
|
|
}
|
2016-02-07 09:48:54 +03:00
|
|
|
// no moar, done w/ headers, get blocks
|
|
|
|
err = s.AskForBlocks()
|
|
|
|
if err != nil {
|
|
|
|
log.Printf("AskForBlocks error: %s", err.Error())
|
|
|
|
return
|
2016-01-29 11:40:52 +03:00
|
|
|
}
|
2016-01-29 09:31:05 +03:00
|
|
|
}
|
|
|
|
|
2016-02-05 12:16:45 +03:00
|
|
|
// TxHandler takes in transaction messages that come in from either a request
|
|
|
|
// after an inv message or after a merkle block message.
|
2016-01-29 09:31:05 +03:00
|
|
|
func (s *SPVCon) TxHandler(m *wire.MsgTx) {
|
2016-02-05 12:16:45 +03:00
|
|
|
s.TS.OKMutex.Lock()
|
|
|
|
height, ok := s.TS.OKTxids[m.TxSha()]
|
|
|
|
s.TS.OKMutex.Unlock()
|
|
|
|
if !ok {
|
2016-02-11 00:22:15 +03:00
|
|
|
log.Printf("Tx %s unknown, will not ingest\n", m.TxSha().String())
|
2016-02-05 12:16:45 +03:00
|
|
|
return
|
|
|
|
}
|
2016-02-07 06:15:35 +03:00
|
|
|
|
|
|
|
// check for double spends
|
|
|
|
allTxs, err := s.TS.GetAllTxs()
|
|
|
|
if err != nil {
|
|
|
|
log.Printf("Can't get txs from db: %s", err.Error())
|
|
|
|
return
|
|
|
|
}
|
|
|
|
dubs, err := CheckDoubleSpends(m, allTxs)
|
|
|
|
if err != nil {
|
|
|
|
log.Printf("CheckDoubleSpends error: %s", err.Error())
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if len(dubs) > 0 {
|
|
|
|
for i, dub := range dubs {
|
|
|
|
fmt.Printf("dub %d known tx %s and new tx %s are exclusive!!!\n",
|
|
|
|
i, dub.String(), m.TxSha().String())
|
|
|
|
}
|
|
|
|
}
|
2016-02-05 12:16:45 +03:00
|
|
|
hits, err := s.TS.Ingest(m, height)
|
2016-01-29 09:31:05 +03:00
|
|
|
if err != nil {
|
|
|
|
log.Printf("Incoming Tx error: %s\n", err.Error())
|
2016-02-05 12:16:45 +03:00
|
|
|
return
|
2016-01-29 09:31:05 +03:00
|
|
|
}
|
2016-02-07 09:48:54 +03:00
|
|
|
if hits == 0 && !s.HardMode {
|
2016-01-29 09:31:05 +03:00
|
|
|
log.Printf("tx %s had no hits, filter false positive.",
|
|
|
|
m.TxSha().String())
|
|
|
|
s.fPositives <- 1 // add one false positive to chan
|
2016-02-05 12:16:45 +03:00
|
|
|
return
|
|
|
|
}
|
|
|
|
log.Printf("tx %s ingested and matches %d utxo/adrs.",
|
|
|
|
m.TxSha().String(), hits)
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetDataHandler responds to requests for tx data, which happen after
|
|
|
|
// advertising our txs via an inv message
|
|
|
|
func (s *SPVCon) GetDataHandler(m *wire.MsgGetData) {
|
|
|
|
log.Printf("got GetData. Contains:\n")
|
|
|
|
var sent int32
|
|
|
|
for i, thing := range m.InvList {
|
|
|
|
log.Printf("\t%d)%s : %s",
|
|
|
|
i, thing.Type.String(), thing.Hash.String())
|
2016-02-18 10:16:17 +03:00
|
|
|
|
|
|
|
// separate wittx and tx. needed / combine?
|
|
|
|
// does the same thing right now
|
|
|
|
if thing.Type == wire.InvTypeWitnessTx {
|
|
|
|
tx, err := s.TS.GetTx(&thing.Hash)
|
|
|
|
if err != nil {
|
|
|
|
log.Printf("error getting tx %s: %s",
|
|
|
|
thing.Hash.String(), err.Error())
|
|
|
|
}
|
2016-02-22 12:41:40 +03:00
|
|
|
fmt.Printf(TxToString(tx))
|
2016-02-18 10:16:17 +03:00
|
|
|
s.outMsgQueue <- tx
|
|
|
|
sent++
|
2016-02-05 12:16:45 +03:00
|
|
|
continue
|
|
|
|
}
|
2016-02-18 10:16:17 +03:00
|
|
|
if thing.Type == wire.InvTypeTx {
|
|
|
|
tx, err := s.TS.GetTx(&thing.Hash)
|
|
|
|
if err != nil {
|
|
|
|
log.Printf("error getting tx %s: %s",
|
|
|
|
thing.Hash.String(), err.Error())
|
|
|
|
}
|
2016-02-22 12:41:40 +03:00
|
|
|
tx.Flags = 0x00 // dewitnessify
|
2016-02-18 10:16:17 +03:00
|
|
|
s.outMsgQueue <- tx
|
|
|
|
sent++
|
|
|
|
continue
|
2016-02-05 12:16:45 +03:00
|
|
|
}
|
2016-02-18 10:16:17 +03:00
|
|
|
// didn't match, so it's not something we're responding to
|
|
|
|
log.Printf("We only respond to tx requests, ignoring")
|
|
|
|
|
2016-01-29 09:31:05 +03:00
|
|
|
}
|
2016-02-05 12:16:45 +03:00
|
|
|
log.Printf("sent %d of %d requested items", sent, len(m.InvList))
|
2016-01-29 09:31:05 +03:00
|
|
|
}
|
|
|
|
|
2016-01-27 12:24:16 +03:00
|
|
|
func (s *SPVCon) InvHandler(m *wire.MsgInv) {
|
|
|
|
log.Printf("got inv. Contains:\n")
|
|
|
|
for i, thing := range m.InvList {
|
|
|
|
log.Printf("\t%d)%s : %s",
|
|
|
|
i, thing.Type.String(), thing.Hash.String())
|
2016-02-07 06:15:35 +03:00
|
|
|
if thing.Type == wire.InvTypeTx {
|
|
|
|
if !s.Ironman { // ignore tx invs in ironman mode
|
|
|
|
// new tx, OK it at 0 and request
|
|
|
|
s.TS.AddTxid(&thing.Hash, 0) // unconfirmed
|
|
|
|
s.AskForTx(thing.Hash)
|
|
|
|
}
|
2016-01-27 12:24:16 +03:00
|
|
|
}
|
2016-02-03 04:14:13 +03:00
|
|
|
if thing.Type == wire.InvTypeBlock { // new block what to do?
|
|
|
|
select {
|
|
|
|
case <-s.inWaitState:
|
|
|
|
// start getting headers
|
2016-01-29 11:40:52 +03:00
|
|
|
fmt.Printf("asking for headers due to inv block\n")
|
2016-02-03 06:04:03 +03:00
|
|
|
err := s.AskForHeaders()
|
|
|
|
if err != nil {
|
|
|
|
log.Printf("AskForHeaders error: %s", err.Error())
|
|
|
|
}
|
2016-02-03 04:14:13 +03:00
|
|
|
default:
|
|
|
|
// drop it as if its component particles had high thermal energies
|
2016-02-03 06:04:03 +03:00
|
|
|
fmt.Printf("inv block but ignoring; not synched\n")
|
2016-01-29 06:35:49 +03:00
|
|
|
}
|
2016-01-27 12:24:16 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|