Ejemplo n.º 1
0
func (getter *HeaderGetter) handleHeaders(m network.Message) bool {
	_, oldHeight := getter.highestKnownBlock()
	headers, err := messages.ParseHeaders(m.Data)
	if err != nil {
		log.Printf("Failed to parse headers: %v", err)
		return true
	}
	log.Printf("Received %d headers from %s.\n",
		len(headers), m.Endpoint)
	var hash []byte
	var height int
	var incomplete bool
	var vector messages.InventoryVector
	for _, h := range headers {
		prevHeight, err := getter.getBlockHeight(h.PrevBlock)
		if err != nil {
			log.Printf("Received bad header %x from %s.",
				utils.ReverseBytes(h.Hash()), m.Endpoint)
			// TODO handle this
			getter.inv.reportMisbehaviour(m.Endpoint, 20,
				"Sent bad block header.")
			incomplete = true
			break
		}
		height = prevHeight + 1
		h.Height = height
		hash = h.Hash()
		getter.db.Set(hash, h)

		// Request merkleblocks for headers.
		vector = append(vector, &messages.Inventory{
			Type: messages.TypeMsgFilteredBlock,
			Hash: hash,
		})
	}
	if len(hash) != 0 && height > oldHeight {
		getter.setHighestKnownBlock(hash, height)
		log.Printf("Last header updated to %x (internal byte order), height is %d.",
			utils.ReverseBytes(hash), height)
		if height < oldHeight+len(vector) {
			// TODO not all blocks are new, consider changing endpoint.
		}
	} else {
		// TODO If we haven't caught up yet, this means the endpoint is
		// misbehaving.
	}
	if len(headers) >= 2000 {
		incomplete = true
	} else {
		// TODO question if endpoint is good.
	}
	err = getter.inv.SendGetData(vector, m.Endpoint)
	if err != nil {
		return true
	}
	return incomplete
}
Ejemplo n.º 2
0
func (getter *HeaderGetter) formGetHeaderMessage() network.Message {
	hash, height := getter.highestKnownBlock()
	msg := messages.GetBlocks{
		Version:  70001,
		HashStop: make([]byte, 32),
		Locators: [][]byte{hash},
	}
	loc := hash
	// Add 20 recent known headers with larger and larger gaps between them
	// as they get less recent (up to a step of 40 between the two least
	// recent ones.)
	for i := 0; i < 20 && loc != nil; i++ {
		for j := 0; j < i*2; j++ {
			header, err := getter.loadHeader(loc)
			if err != nil {
				log.Printf("Failed to get recent header, %d steps back: %v",
					i, err)
				loc = nil
				break
			}
			loc = header.PrevBlock
		}
		if loc != nil {
			msg.Locators = append(msg.Locators, loc)
		}
	}
	var msgBytes bytes.Buffer
	msg.Serialize(&msgBytes)
	log.Printf("Getting more headers, starting from %x at height %d.\n",
		utils.ReverseBytes(hash), height)
	return network.Message{
		Type: "getheaders",
		Data: msgBytes.Bytes(),
	}
}
Ejemplo n.º 3
0
func (inv *Inventory) handleMerkleBlock(m network.Message) {
	block, err := messages.ParseMerkleBlock(m.Data)
	if err != nil {
		log.Printf("Failed to parse merkleblock: %v", err)
		return
	}
	if len(block.Flags) > 1 || block.Flags[0] != 0x00 {
		log.Printf("Merkleblock %x flags %x",
			utils.ReverseBytes(block.Hash()),
			block.Flags)
		root, err := NewMerkleTree(block.TotalTXs,
			block.Hashes, block.Flags)
		if err != nil || !bytes.Equal(root.Hash, block.MerkleRoot) {
			log.Printf("Merkle hash mismatch!")
			for _, h := range block.Hashes {
				log.Printf("Input hashes: %x", h)
			}
			log.Printf("Calculated merkle hash %x, "+
				"expected %x. %d matched transactions.",
				root.Hash, block.MerkleRoot,
				len(root.MatchedTransactions()))
			// TODO handle this without panicking.
			panic(fmt.Sprintf("TotalTXs %d, Flags %x",
				block.TotalTXs, block.Flags))
		}
		height, err := inv.headers.getBlockHeight(block.PrevBlock)
		if err != nil {
			// TODO This indicates that we're not caught up yet,
			// which can be useful information if we're receiving
			// short header lists from a bad node.
			// TODO Send a getheaders request.
			log.Printf("Couldn't figure out height of block: %v", err)
		} else {
			// Only store block if we known the height.
			height += 1
			block.Height = height
			inv.config.Database.Set(block.Hash(), block)

			log.Printf("Received Merkleheaders for block %d", height)
			_, highest := inv.headers.highestKnownBlock()
			if height > highest {
				inv.headers.setHighestKnownBlock(block.Hash(), height)
				log.Printf("Updated highest known block.")
			}
		}
		// Store transactions even if we couldn't get correct height.
		// TODO Update height value once we figure it out.
		short := Block{
			Hash:      block.Hash(),
			Timestamp: time.Unix(int64(block.Timestamp), 0),
			Height:    int32(height),
		}
		// Attach block information to transactions
		for _, tx := range root.MatchedTransactions() {
			// TODO Check against local filter.
			inv.addTxBlock(tx, &short)
		}
	}
}
Ejemplo n.º 4
0
func (t TxVersion) String() string {
	str := fmt.Sprintf("Transaction %x", utils.ReverseBytes(t.Hash))
	if t.tx != nil {
		str += fmt.Sprintf(" fingerprint %x", t.Id())
	}
	if t.Block != nil {
		str += fmt.Sprintf(" in block %x (height %d)", t.Block.Hash, t.Block.Height)
	}
	return str
}
Ejemplo n.º 5
0
func (getter *HeaderGetter) getBlockHeight(hash []byte) (int, error) {
	prev, err := getter.loadHeader(hash)
	if err != nil {
		block0, _ := hex.DecodeString(
			"000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f")
		if bytes.Equal(hash, utils.ReverseBytes(block0)) {
			return 0, nil
		}
		return -1, fmt.Errorf("Couldn't find prev block.")
	}
	return int(prev.Height), nil
}
Ejemplo n.º 6
0
func (a *Account) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "text/html")
	a.UpdateBalances()
	fmt.Fprintf(w, "\n<p>Receive addresses:</p>\n")
	for i, name := range a.recvAddrList {
		addr := a.addrMap[name]
		encoded, _ := base58.BitcoinCheckEncode(
			base58.BitcoinPublicKeyHashPrefix, []byte(name))
		// TODO get account numnber right.
		fmt.Fprintf(w, "m/44'/0'/0'/0/%d: %s,  balance: %d\n<br>",
			i, encoded, addr.Balance())
		for _, s := range addr.spendables {
			fmt.Fprintf(w, "Spendable output from tx %x (fingerprint):<br>",
				s.outputs[0].TxFingerprint())
			for _, o := range s.outputs {
				fmt.Fprintf(w, "tx %x (hash, internal byte order) (index %d): "+
					"%d satoshi\n<br>",
					utils.ReverseBytes(o.TxHash()), o.Index(), o.Value)
			}
		}
	}
	fmt.Fprintf(w, "\n<p>Change addresses:</p>\n")
	for i, name := range a.changeAddrList {
		addr := a.addrMap[name]
		encoded, _ := base58.BitcoinCheckEncode(
			base58.BitcoinPublicKeyHashPrefix, []byte(name))
		// TODO get account numnber right.
		fmt.Fprintf(w, "m/44'/0'/0'/1/%d: %s,  balance: %d\n<br>",
			i, encoded, addr.Balance())
		for _, s := range addr.spendables {
			fmt.Fprintf(w, "Spendable output from tx %x (fingerprint):<br>",
				s.outputs[0].TxFingerprint())
			for _, o := range s.outputs {
				fmt.Fprintf(w, "tx %x (hash, internal byte order) (index %d): "+
					"%d satoshi\n<br>",
					utils.ReverseBytes(o.TxHash()), o.Index(), o.Value)
			}
		}
	}
}
Ejemplo n.º 7
0
func (b *Block) String() string {
	str := fmt.Sprintf("%x, version %d\n", utils.ReverseBytes(b.Hash), b.Version)
	str += fmt.Sprintf("PrevBlock: %x\n", b.PrevBlock)
	str += fmt.Sprintf("MerkleRoot: %x\n", b.MerkleRoot)
	str += fmt.Sprintf("Timestamp: %s (%d)\n",
		time.Unix(int64(b.Timestamp), 0), b.Timestamp)
	str += fmt.Sprintf("Bits: 0x%x\n", b.Bits)
	str += fmt.Sprintf("Transactions (%d):\n", len(b.Transactions))
	for i, tx := range b.Transactions {
		str += fmt.Sprintf("TX %d: %s\n", i, tx)
	}
	return str
}
Ejemplo n.º 8
0
func (t *Transaction) String() string {
	str := fmt.Sprintf("%x, version %d\n\n",
		utils.ReverseBytes(t.Hash()), t.Version)
	for _, i := range t.Inputs {
		str += fmt.Sprintf("%s\n\n", i)
	}
	for _, o := range t.Outputs {
		str += fmt.Sprintf("%s\n", o)
	}
	str += fmt.Sprintf("\n")
	if t.LockTime == 0 {
		str += fmt.Sprintf("Unlocked.")
	} else {
		str += fmt.Sprintf("Locktime %d.", t.LockTime)
	}
	return str
}
Ejemplo n.º 9
0
func (t *Transaction) MatchesFilter(filter *FilterLoad) bool {
	if filter.MayContain(t.Hash()) {
		return true
	}
	if filter.MayContain(utils.ReverseBytes(t.Hash())) {
		log.Printf("Tx matched reverse hash: %x", t.Hash)
		return true
	}
	for _, o := range t.Outputs {
		if o.MatchesFilter(filter) {
			return true
		}
	}
	for _, i := range t.Inputs {
		if i.MatchesFilter(filter) {
			return true
		}
	}
	return false
}
Ejemplo n.º 10
0
func (t *Transaction) HashInternal() string {
	r := utils.ReverseBytes(t.Hash())
	return fmt.Sprintf("%x (internal byte order)", r)
}
Ejemplo n.º 11
0
func (p OutPoint) String() string {
	return fmt.Sprintf("%x (output index %d)", utils.ReverseBytes(p.Hash), p.Index)
}
Ejemplo n.º 12
0
// UpdateTxOutputs updates the list of unspent transaction outputs Inventory is
// watching. It also alerts attached wallets about new transaction to aid their
// discovery process.
func (inv *Inventory) UpdateTxOutputs(version *TxVersion) error {
	// TODO protect against races.
	tx := version.tx
	if tx == nil {
		return fmt.Errorf("Input has no transaction associated with it.")
	}
	id := tx.Fingerprint()

	// Check if new transaction spends one of our unspent outputs.
	for _, i := range tx.Inputs {
		prev := i.PreviousOutput
		outputId := Fingerprint(prev.Hash, prev.Index)
		out, found := inv.outputs[string(outputId)]
		if found {
			//			log.Printf("Output %d of tx %x spent by input %d of tx %x.",
			//				prev.Index, out.TxHash(), index, tx.Hash())
			out.spentBy = tx
		}
	}

	var outputs []*TxOutput
	// Check if new transaction pays any of our addresses.
	for index, o := range tx.Outputs {
		addr := o.AddressHash()
		if addr != nil {
			if inv.filter.Match(addr) {
				// This is an exact match, but not just for
				// public address hashes. Either way, it's
				// highly likely that this is an output that we
				// can spend, so add it to the list and let the
				// wallets filter out the ones they can spend.
				encoded, _ := base58.BitcoinCheckEncode(
					base58.BitcoinPublicKeyHashPrefix, addr)
				output := TxOutput{
					index:  uint32(index),
					output: o,
					tx:     version,
					id:     id,
				}
				log.Printf("Transaction hash %x pays address %s with output %x",
					utils.ReverseBytes(tx.Hash()), encoded, output.Fingerprint())
				inv.outputs[string(output.Fingerprint())] = &output
				outputs = append(outputs, &output)

				if inv.config.Wallet != nil {
					inv.config.Wallet.MarkAddressAsUsed(addr)
				}
			}
		}
	}

	// Check if we already know a transaction that spends the new outputs.
	for _, o := range outputs {
		for _, version := range inv.txHashes {
			t := version.tx
			if t == nil {
				continue
			}
			for _, i := range t.Inputs {
				prev := i.PreviousOutput
				if bytes.Equal(prev.Hash, o.TxHash()) && prev.Index == o.index {
					//					log.Printf("Output %x(%d) already spent by input %x(%d).",
					//						o.TxHash(), prev.Index, t.Hash(), index)
					o.spentBy = t
				}
			}
		}
	}
	return nil
}