コード例 #1
0
ファイル: tx.go プロジェクト: runeaune/btcd
func (db *LevelDb) getData(data []byte) ([]database.TxData, error) {
	var list []database.TxData
	key := dataToKey(data, nil, 0)
	iter := db.lDb.NewIterator(util.BytesPrefix(key), nil)
	for iter.Next() {
		item := database.TxData{}
		val := iter.Value()
		var err error
		if len(val) == 32 { // TODO remove this once db has been updated.
			item.TxSha, err = wire.NewShaHash(val)
			if err != nil {
				return nil, err
			}
		} else if len(val) == 72 {
			item.TxSha, err = wire.NewShaHash(val[0:32])
			if err != nil {
				return nil, err
			}
			item.BlockSha, err = wire.NewShaHash(val[32:64])
			if err != nil {
				return nil, err
			}
			b := bytes.NewBuffer(val[64:72])
			binary.Read(b, binary.LittleEndian, &item.Time)
		} else {
			return nil, fmt.Errorf("Non-standard length %d", len(val))
		}
		list = append(list, item)
	}
	iter.Release()
	if err := iter.Error(); err != nil {
		return nil, err
	}
	return list, nil
}
コード例 #2
0
ファイル: server.go プロジェクト: jimmysong/btcwallet
// BUGS:
// - MinimumRecentTransactions is ignored.
// - Wrong error codes when a block height or hash is not recognized
func (s *walletServer) GetTransactions(ctx context.Context, req *pb.GetTransactionsRequest) (
	resp *pb.GetTransactionsResponse, err error) {

	var startBlock, endBlock *wallet.BlockIdentifier
	if req.StartingBlockHash != nil && req.StartingBlockHeight != 0 {
		return nil, errors.New(
			"starting block hash and height may not be specified simultaneously")
	} else if req.StartingBlockHash != nil {
		startBlockHash, err := wire.NewShaHash(req.StartingBlockHash)
		if err != nil {
			return nil, grpc.Errorf(codes.InvalidArgument, "%s", err.Error())
		}
		startBlock = wallet.NewBlockIdentifierFromHash(startBlockHash)
	} else if req.StartingBlockHeight != 0 {
		startBlock = wallet.NewBlockIdentifierFromHeight(req.StartingBlockHeight)
	}

	if req.EndingBlockHash != nil && req.EndingBlockHeight != 0 {
		return nil, grpc.Errorf(codes.InvalidArgument,
			"ending block hash and height may not be specified simultaneously")
	} else if req.EndingBlockHash != nil {
		endBlockHash, err := wire.NewShaHash(req.EndingBlockHash)
		if err != nil {
			return nil, grpc.Errorf(codes.InvalidArgument, "%s", err.Error())
		}
		endBlock = wallet.NewBlockIdentifierFromHash(endBlockHash)
	} else if req.EndingBlockHeight != 0 {
		endBlock = wallet.NewBlockIdentifierFromHeight(req.EndingBlockHeight)
	}

	var minRecentTxs int
	if req.MinimumRecentTransactions != 0 {
		if endBlock != nil {
			return nil, grpc.Errorf(codes.InvalidArgument,
				"ending block and minimum number of recent transactions "+
					"may not be specified simultaneously")
		}
		minRecentTxs = int(req.MinimumRecentTransactions)
		if minRecentTxs < 0 {
			return nil, grpc.Errorf(codes.InvalidArgument,
				"minimum number of recent transactions may not be negative")
		}
	}

	_ = minRecentTxs

	gtr, err := s.wallet.GetTransactions(startBlock, endBlock, ctx.Done())
	if err != nil {
		return nil, translateError(err)
	}
	return marshalGetTransactionsResult(gtr)
}
コード例 #3
0
func NewCoin(txid []byte, index uint32, value btc.Amount, numConfs int64, scriptPubKey []byte) coinset.Coin {
	shaTxid, _ := wire.NewShaHash(txid)
	c := &Coin{
		TxHash:       shaTxid,
		TxIndex:      index,
		TxValue:      value,
		TxNumConfs:   numConfs,
		ScriptPubKey: scriptPubKey,
	}
	return coinset.Coin(c)
}
コード例 #4
0
ファイル: coins_test.go プロジェクト: CrowBits/btcutil
func NewCoin(index int64, value btcutil.Amount, numConfs int64) coinset.Coin {
	h := fastsha256.New()
	h.Write([]byte(fmt.Sprintf("%d", index)))
	hash, _ := wire.NewShaHash(h.Sum(nil))
	c := &TestCoin{
		TxHash:     hash,
		TxIndex:    0,
		TxValue:    value,
		TxNumConfs: numConfs,
	}
	return coinset.Coin(c)
}
コード例 #5
0
ファイル: merkle.go プロジェクト: jimmysong/btcd
// HashMerkleBranches takes two hashes, treated as the left and right tree
// nodes, and returns the hash of their concatenation.  This is a helper
// function used to aid in the generation of a merkle tree.
func HashMerkleBranches(left *wire.ShaHash, right *wire.ShaHash) *wire.ShaHash {
	// Concatenate the left and right nodes.
	var sha [wire.HashSize * 2]byte
	copy(sha[:wire.HashSize], left.Bytes())
	copy(sha[wire.HashSize:], right.Bytes())

	// Create a new sha hash from the double sha 256.  Ignore the error
	// here since SetBytes can't fail here due to the fact DoubleSha256
	// always returns a []byte of the right size regardless of input.
	newSha, _ := wire.NewShaHash(wire.DoubleSha256(sha[:]))
	return newSha
}
コード例 #6
0
// BenchmarkMruInventoryList performs basic benchmarks on the most recently
// used inventory handling.
func BenchmarkMruInventoryList(b *testing.B) {
	// Create a bunch of fake inventory vectors to use in benchmarking
	// the mru inventory code.
	b.StopTimer()
	numInvVects := 100000
	invVects := make([]*wire.InvVect, 0, numInvVects)
	for i := 0; i < numInvVects; i++ {
		hashBytes := make([]byte, wire.HashSize)
		rand.Read(hashBytes)
		hash, _ := wire.NewShaHash(hashBytes)
		iv := wire.NewInvVect(wire.InvTypeBlock, hash)
		invVects = append(invVects, iv)
	}
	b.StartTimer()

	// Benchmark the add plus evicition code.
	limit := 20000
	mruInvMap := NewMruInventoryMap(uint(limit))
	for i := 0; i < b.N; i++ {
		mruInvMap.Add(invVects[i%numInvVects])
	}
}
コード例 #7
0
ファイル: wallet_test.go プロジェクト: martindale/lnd
// genBlockHash deterministically generates a dummy block header hash for use
// within our tests below.
func genBlockHash(n int) *wire.ShaHash {
	sha := sha256.Sum256([]byte{byte(n)})
	hash, _ := wire.NewShaHash(sha[:])
	return hash
}
コード例 #8
0
ファイル: shahash_test.go プロジェクト: vineventura/btcd
// TestShaHash tests the ShaHash API.
func TestShaHash(t *testing.T) {

	// Hash of block 234439.
	blockHashStr := "14a0810ac680a3eb3f82edc878cea25ec41d6b790744e5daeef"
	blockHash, err := wire.NewShaHashFromStr(blockHashStr)
	if err != nil {
		t.Errorf("NewShaHashFromStr: %v", err)
	}

	// Hash of block 234440 as byte slice.
	buf := []byte{
		0x79, 0xa6, 0x1a, 0xdb, 0xc6, 0xe5, 0xa2, 0xe1,
		0x39, 0xd2, 0x71, 0x3a, 0x54, 0x6e, 0xc7, 0xc8,
		0x75, 0x63, 0x2e, 0x75, 0xf1, 0xdf, 0x9c, 0x3f,
		0xa6, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	}

	hash, err := wire.NewShaHash(buf)
	if err != nil {
		t.Errorf("NewShaHash: unexpected error %v", err)
	}

	// Ensure proper size.
	if len(hash) != wire.HashSize {
		t.Errorf("NewShaHash: hash length mismatch - got: %v, want: %v",
			len(hash), wire.HashSize)
	}

	// Ensure contents match.
	if !bytes.Equal(hash[:], buf) {
		t.Errorf("NewShaHash: hash contents mismatch - got: %v, want: %v",
			hash[:], buf)
	}

	// Ensure contents of hash of block 234440 don't match 234439.
	if hash.IsEqual(blockHash) {
		t.Errorf("IsEqual: hash contents should not match - got: %v, want: %v",
			hash, blockHash)
	}

	// Set hash from byte slice and ensure contents match.
	err = hash.SetBytes(blockHash.Bytes())
	if err != nil {
		t.Errorf("SetBytes: %v", err)
	}
	if !hash.IsEqual(blockHash) {
		t.Errorf("IsEqual: hash contents mismatch - got: %v, want: %v",
			hash, blockHash)
	}

	// Invalid size for SetBytes.
	err = hash.SetBytes([]byte{0x00})
	if err == nil {
		t.Errorf("SetBytes: failed to received expected err - got: nil")
	}

	// Invalid size for NewShaHash.
	invalidHash := make([]byte, wire.HashSize+1)
	_, err = wire.NewShaHash(invalidHash)
	if err == nil {
		t.Errorf("NewShaHash: failed to received expected err - got: nil")
	}
}
コード例 #9
0
ファイル: msgmerkleblock_test.go プロジェクト: jimmysong/btcd
// TestMerkleBlock tests the MsgMerkleBlock API.
func TestMerkleBlock(t *testing.T) {
	pver := wire.ProtocolVersion

	// Block 1 header.
	prevHash := &blockOne.Header.PrevBlock
	merkleHash := &blockOne.Header.MerkleRoot
	bits := blockOne.Header.Bits
	nonce := blockOne.Header.Nonce
	bh := wire.NewBlockHeader(prevHash, merkleHash, bits, nonce)

	// Ensure the command is expected value.
	wantCmd := "merkleblock"
	msg := wire.NewMsgMerkleBlock(bh)
	if cmd := msg.Command(); cmd != wantCmd {
		t.Errorf("NewMsgBlock: wrong command - got %v want %v",
			cmd, wantCmd)
	}

	// Ensure max payload is expected value for latest protocol version.
	// Num addresses (varInt) + max allowed addresses.
	wantPayload := uint32(1000000)
	maxPayload := msg.MaxPayloadLength(pver)
	if maxPayload != wantPayload {
		t.Errorf("MaxPayloadLength: wrong max payload length for "+
			"protocol version %d - got %v, want %v", pver,
			maxPayload, wantPayload)
	}

	// Load maxTxPerBlock hashes
	data := make([]byte, 32)
	for i := 0; i < wire.MaxTxPerBlock; i++ {
		rand.Read(data)
		hash, err := wire.NewShaHash(data)
		if err != nil {
			t.Errorf("NewShaHash failed: %v\n", err)
			return
		}

		if err = msg.AddTxHash(hash); err != nil {
			t.Errorf("AddTxHash failed: %v\n", err)
			return
		}
	}

	// Add one more Tx to test failure.
	rand.Read(data)
	hash, err := wire.NewShaHash(data)
	if err != nil {
		t.Errorf("NewShaHash failed: %v\n", err)
		return
	}

	if err = msg.AddTxHash(hash); err == nil {
		t.Errorf("AddTxHash succeeded when it should have failed")
		return
	}

	// Test encode with latest protocol version.
	var buf bytes.Buffer
	err = msg.BtcEncode(&buf, pver)
	if err != nil {
		t.Errorf("encode of MsgMerkleBlock failed %v err <%v>", msg, err)
	}

	// Test decode with latest protocol version.
	readmsg := wire.MsgMerkleBlock{}
	err = readmsg.BtcDecode(&buf, pver)
	if err != nil {
		t.Errorf("decode of MsgMerkleBlock failed [%v] err <%v>", buf, err)
	}

	// Force extra hash to test maxTxPerBlock.
	msg.Hashes = append(msg.Hashes, hash)
	err = msg.BtcEncode(&buf, pver)
	if err == nil {
		t.Errorf("encode of MsgMerkleBlock succeeded with too many " +
			"tx hashes when it should have failed")
		return
	}

	// Force too many flag bytes to test maxFlagsPerMerkleBlock.
	// Reset the number of hashes back to a valid value.
	msg.Hashes = msg.Hashes[len(msg.Hashes)-1:]
	msg.Flags = make([]byte, wire.MaxFlagsPerMerkleBlock+1)
	err = msg.BtcEncode(&buf, pver)
	if err == nil {
		t.Errorf("encode of MsgMerkleBlock succeeded with too many " +
			"flag bytes when it should have failed")
		return
	}
}
コード例 #10
0
ファイル: lnwire_test.go プロジェクト: PaulCapestany/lnd
	address         = pubKey

	//  Delivery PkScript
	// Privkey: f2c00ead9cbcfec63098dc0a5f152c0165aff40a2ab92feb4e24869a284c32a7
	// PKhash: n2fkWVphUzw3zSigzPsv9GuDyg9mohzKpz
	deliveryPkScript, _ = hex.DecodeString("76a914e8048c0fb75bdecc91ebfb99c174f4ece29ffbd488ac")

	//  Change PkScript
	// Privkey: 5b18f5049efd9d3aff1fb9a06506c0b809fb71562b6ecd02f6c5b3ab298f3b0f
	// PKhash: miky84cHvLuk6jcT6GsSbgHR8d7eZCu9Qc
	changePkScript, _ = hex.DecodeString("76a914238ee44bb5c8c1314dd03974a17ec6c406fdcb8388ac")

	// echo -n | openssl sha256
	// This stuff gets reversed!!!
	shaHash1Bytes, _ = hex.DecodeString("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855")
	shaHash1, _      = wire.NewShaHash(shaHash1Bytes)
	outpoint1        = wire.NewOutPoint(shaHash1, 0)
	// echo | openssl sha256
	// This stuff gets reversed!!!
	shaHash2Bytes, _ = hex.DecodeString("01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b")
	shaHash2, _      = wire.NewShaHash(shaHash2Bytes)
	outpoint2        = wire.NewOutPoint(shaHash2, 1)
	// create inputs from outpoint1 and outpoint2
	inputs = []*wire.TxIn{wire.NewTxIn(outpoint1, nil), wire.NewTxIn(outpoint2, nil)}

	// Commitment Signature
	tx           = wire.NewMsgTx()
	emptybytes   = new([]byte)
	sigStr, _    = txscript.RawTxInSignature(tx, 0, *emptybytes, txscript.SigHashAll, privKey)
	commitSig, _ = btcec.ParseSignature(sigStr, btcec.S256())
コード例 #11
0
func (l *LibbitcoinClient) Parse(command string, data []byte, callback func(interface{}, error)) {
	switch command {
	case "address.fetch_history2":
		numRows := (len(data) - 4) / 49
		buff := bytes.NewBuffer(data)
		err := ParseError(buff.Next(4))
		rows := []FetchHistory2Resp{}
		for i := 0; i < numRows; i++ {
			r := FetchHistory2Resp{}
			spendByte := int(buff.Next(1)[0])
			var spendBool bool
			if spendByte == 0 {
				spendBool = false
			} else {
				spendBool = true
			}
			r.IsSpend = spendBool
			lehash := buff.Next(32)
			sh, _ := wire.NewShaHash(lehash)
			r.TxHash = sh.String()
			indexBytes := buff.Next(4)
			r.Index = binary.LittleEndian.Uint32(indexBytes)
			heightBytes := buff.Next(4)
			r.Height = binary.LittleEndian.Uint32(heightBytes)
			valueBytes := buff.Next(8)
			r.Value = binary.LittleEndian.Uint64(valueBytes)
			rows = append(rows, r)
		}
		callback(rows, err)
	case "blockchain.fetch_last_height":
		height := binary.LittleEndian.Uint32(data[4:])
		callback(height, ParseError(data[:4]))
	case "blockchain.fetch_transaction":
		txn, _ := btc.NewTxFromBytes(data[4:])
		callback(txn, ParseError(data[:4]))
	case "transaction_pool.fetch_transaction":
		txn, _ := btc.NewTxFromBytes(data[4:])
		callback(txn, ParseError(data[:4]))
	case "address.update":
		buff := bytes.NewBuffer(data)
		addressVersion := buff.Next(1)[0]
		addressHash160 := buff.Next(20)
		height := buff.Next(4)
		block := buff.Next(32)
		tx := buff.Bytes()

		var addr btc.Address
		if addressVersion == byte(111) || addressVersion == byte(0) {
			a, _ := btc.NewAddressPubKeyHash(addressHash160, l.Params)
			addr = a
		} else if addressVersion == byte(5) || addressVersion == byte(196) {
			a, _ := btc.NewAddressScriptHashFromHash(addressHash160, l.Params)
			addr = a
		}
		bl, _ := wire.NewShaHash(block)
		txn, _ := btc.NewTxFromBytes(tx)

		resp := SubscribeResp{
			Address: addr.String(),
			Height:  binary.LittleEndian.Uint32(height),
			Block:   bl.String(),
			Tx:      *txn,
		}
		l.lock.Lock()
		l.subscriptions[addr.String()].callback(resp)
		l.lock.Unlock()
	case "protocol.broadcast_transaction":
		callback(nil, ParseError(data[:4]))
	case "transaction_pool.validate":
		b := data[4:5]
		success, _ := strconv.ParseBool(string(b))
		callback(success, ParseError(data[:4]))
	}
}
コード例 #12
0
ファイル: insertremove_test.go プロジェクト: runeaune/btcd
func TestInsertData(t *testing.T) {
	// Ignore db remove errors since it means we didn't have an old one.
	dbname := fmt.Sprintf("tstdbdata1")
	dbnamever := dbname + ".ver"
	_ = os.RemoveAll(dbname)
	_ = os.RemoveAll(dbnamever)
	db, err := database.CreateDB("leveldb", dbname)
	if err != nil {
		t.Fatalf("Failed to open test database %v", err)
	}

	defer os.RemoveAll(dbname)
	defer os.RemoveAll(dbnamever)
	defer func() {
		if err := db.Close(); err != nil {
			t.Errorf("Close: unexpected error: %v", err)
		}
	}()

	list, err := db.FetchTxsByData([]byte("dhaskj2"))
	if err != nil {
		t.Fatalf("Get data failed %v", err)
	}
	if len(list) != 0 {
		t.Errorf("Expected empty list, got length %d.", len(list))
	}

	txSha0, err := wire.NewShaHash([]byte("00001111222233334444555566667777"))
	if err != nil {
		t.Fatalf("Failed to set-up ShaHash %v", err)
	}
	txSha1, err := wire.NewShaHash([]byte("10001111222233334444555566667777"))
	if err != nil {
		t.Fatalf("Failed to set-up ShaHash %v", err)
	}
	err = db.InsertData([]byte("dhaskj1"), txSha0, 0)
	if err != nil {
		t.Fatalf("Insert data failed %v", err)
	}

	list, err = db.FetchTxsByData([]byte("dhaskj2"))
	if err != nil {
		t.Fatalf("Get data failed %v", err)
	}
	if len(list) != 0 {
		t.Errorf("Expected empty list, got length %d.", len(list))
	}

	err = db.InsertData([]byte("dhaskj2"), txSha0, 0)
	if err != nil {
		t.Fatalf("Insert data failed %v", err)
	}
	err = db.InsertData([]byte("dhaskj2"), txSha1, 0)
	if err != nil {
		t.Fatalf("Insert data failed %v", err)
	}

	list, err = db.FetchTxsByData([]byte("dhaskj2"))
	if err != nil {
		t.Fatalf("Get data failed %v", err)
	}
	if len(list) != 2 {
		t.Errorf("Expected list with 2 items, got %d.", len(list))
	}
}
コード例 #13
0
ファイル: lnwire.go プロジェクト: martindale/lnd
func readElement(r io.Reader, element interface{}) error {
	var err error
	switch e := element.(type) {
	case *uint8:
		var b [1]uint8
		_, err = r.Read(b[:])
		if err != nil {
			return err
		}
		*e = b[0]
		return nil
	case *uint16:
		var b [2]byte
		_, err = io.ReadFull(r, b[:])
		if err != nil {
			return err
		}
		*e = binary.BigEndian.Uint16(b[:])
		return nil
	case *CreditsAmount:
		var b [4]byte
		_, err = io.ReadFull(r, b[:])
		if err != nil {
			return err
		}
		*e = CreditsAmount(int32(binary.BigEndian.Uint32(b[:])))
		return nil
	case *uint32:
		var b [4]byte
		_, err = io.ReadFull(r, b[:])
		if err != nil {
			return err
		}
		*e = binary.BigEndian.Uint32(b[:])
		return nil
	case *uint64:
		var b [8]byte
		_, err = io.ReadFull(r, b[:])
		if err != nil {
			return err
		}
		*e = binary.BigEndian.Uint64(b[:])
		return nil
	case *HTLCKey:
		var b [8]byte
		_, err = io.ReadFull(r, b[:])
		if err != nil {
			return err
		}
		*e = HTLCKey(binary.BigEndian.Uint64(b[:]))
		return nil
	case *btcutil.Amount:
		var b [8]byte
		_, err = io.ReadFull(r, b[:])
		if err != nil {
			return err
		}
		*e = btcutil.Amount(int64(binary.BigEndian.Uint64(b[:])))
		return nil
	case **wire.ShaHash:
		var b wire.ShaHash
		_, err = io.ReadFull(r, b[:])
		if err != nil {
			return err
		}
		*e = &b
		return nil
	case **btcec.PublicKey:
		var b [33]byte
		_, err = io.ReadFull(r, b[:])
		if err != nil {
			return err
		}
		x, err := btcec.ParsePubKey(b[:], btcec.S256())
		if err != nil {
			return err
		}
		*e = &*x
		return nil
	case *[]uint64:
		var numItems uint16
		err = readElement(r, &numItems)
		if err != nil {
			return err
		}
		// if numItems > 65535 {
		// 	return fmt.Errorf("Too many items in []uint64")
		// }

		// Read the number of items
		var items []uint64
		for i := uint16(0); i < numItems; i++ {
			var item uint64
			err = readElement(r, &item)
			if err != nil {
				return err
			}
			items = append(items, item)
		}
		*e = *&items
		return nil
	case *[]*btcec.Signature:
		var numSigs uint8
		err = readElement(r, &numSigs)
		if err != nil {
			return err
		}
		if numSigs > 127 {
			return fmt.Errorf("Too many signatures!")
		}

		// Read that number of signatures
		var sigs []*btcec.Signature
		for i := uint8(0); i < numSigs; i++ {
			sig := new(btcec.Signature)
			err = readElement(r, &sig)
			if err != nil {
				return err
			}
			sigs = append(sigs, sig)
		}
		*e = *&sigs
		return nil
	case **btcec.Signature:
		var sigLength uint8
		err = readElement(r, &sigLength)
		if err != nil {
			return err
		}

		if sigLength > 73 {
			return fmt.Errorf("Signature too long!")
		}

		// Read the sig length
		l := io.LimitReader(r, int64(sigLength))
		sig, err := ioutil.ReadAll(l)
		if err != nil {
			return err
		}
		if len(sig) != int(sigLength) {
			return fmt.Errorf("EOF: Signature length mismatch.")
		}
		btcecSig, err := btcec.ParseSignature(sig, btcec.S256())
		if err != nil {
			return err
		}
		*e = &*btcecSig
		return nil
	case *[]*[20]byte:
		// How many to read
		var sliceSize uint16
		err = readElement(r, &sliceSize)
		if err != nil {
			return err
		}
		var data []*[20]byte
		// Append the actual
		for i := uint16(0); i < sliceSize; i++ {
			var element [20]byte
			err = readElement(r, &element)
			if err != nil {
				return err
			}
			data = append(data, &element)
		}
		*e = data
		return nil
	case *[20]byte:
		_, err = io.ReadFull(r, e[:])
		if err != nil {
			return err
		}
		return nil
	case *wire.BitcoinNet:
		var b [4]byte
		_, err := io.ReadFull(r, b[:])
		if err != nil {
			return err
		}
		*e = wire.BitcoinNet(binary.BigEndian.Uint32(b[:]))
		return nil
	case *[]byte:
		// Get the blob length first
		var blobLength uint16
		err = readElement(r, &blobLength)
		if err != nil {
			return err
		}

		// Shouldn't need to do this, since it's uint16, but we
		// might have a different value for MAX_SLICE_LENGTH...
		if int(blobLength) > MAX_SLICE_LENGTH {
			return fmt.Errorf("Slice length too long!")
		}

		// Read the slice length
		l := io.LimitReader(r, int64(blobLength))
		*e, err = ioutil.ReadAll(l)
		if err != nil {
			return err
		}
		if len(*e) != int(blobLength) {
			return fmt.Errorf("EOF: Slice length mismatch.")
		}
		return nil
	case *PkScript:
		// Get the script length first
		var scriptLength uint8
		err = readElement(r, &scriptLength)
		if err != nil {
			return err
		}

		if scriptLength > 25 {
			return fmt.Errorf("PkScript too long!")
		}

		// Read the script length
		l := io.LimitReader(r, int64(scriptLength))
		*e, err = ioutil.ReadAll(l)
		if err != nil {
			return err
		}
		if len(*e) != int(scriptLength) {
			return fmt.Errorf("EOF: Signature length mismatch.")
		}
		return nil
	case *string:
		// Get the string length first
		var strlen uint16
		err = readElement(r, &strlen)
		if err != nil {
			return err
		}
		// Read the string for the length
		l := io.LimitReader(r, int64(strlen))
		b, err := ioutil.ReadAll(l)
		if len(b) != int(strlen) {
			return fmt.Errorf("EOF: String length mismatch.")
		}
		*e = string(b)
		if err != nil {
			return err
		}
		return nil
	case *[]*wire.TxIn:
		// Read the size (1-byte number of txins)
		var numScripts uint8
		err = readElement(r, &numScripts)
		if err != nil {
			return err
		}
		if numScripts > 127 {
			return fmt.Errorf("Too many txins")
		}

		// Append the actual TxIns
		var txins []*wire.TxIn
		for i := uint8(0); i < numScripts; i++ {
			outpoint := new(wire.OutPoint)
			txin := wire.NewTxIn(outpoint, nil)
			err = readElement(r, &txin)
			if err != nil {
				return err
			}
			txins = append(txins, txin)
		}
		*e = *&txins
		return nil
	case **wire.TxIn:
		// Hash
		var h [32]byte
		_, err = io.ReadFull(r, h[:])
		if err != nil {
			return err
		}
		hash, err := wire.NewShaHash(h[:])
		if err != nil {
			return err
		}
		(*e).PreviousOutPoint.Hash = *hash
		// Index
		var idxBytes [4]byte
		_, err = io.ReadFull(r, idxBytes[:])
		if err != nil {
			return err
		}
		(*e).PreviousOutPoint.Index = binary.BigEndian.Uint32(idxBytes[:])
		return nil
	default:
		return fmt.Errorf("Unknown type in readElement: %T", e)
	}

	return nil
}