Exemple #1
0
func assertAddrIndexTipIsUpdated(db database.Db, t *testing.T, newestSha *wire.ShaHash, newestBlockIdx int32) {
	// Safe to ignore error, since height will be < 0 in "error" case.
	sha, height, _ := db.FetchAddrIndexTip()
	if newestBlockIdx != height {
		t.Fatalf("Height of address index tip failed to update, "+
			"expected %v, got %v", newestBlockIdx, height)
	}
	if !bytes.Equal(newestSha.Bytes(), sha.Bytes()) {
		t.Fatalf("Sha of address index tip failed to update, "+
			"expected %v, got %v", newestSha, sha)
	}
}
Exemple #2
0
// 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
}
Exemple #3
0
// ShaHashToBig converts a wire.ShaHash into a big.Int that can be used to
// perform math comparisons.
func ShaHashToBig(hash *wire.ShaHash) *big.Int {
	// A ShaHash is in little-endian, but the big package wants the bytes
	// in big-endian.  Reverse them.  ShaHash.Bytes makes a copy, so it
	// is safe to modify the returned buffer.
	buf := hash.Bytes()
	blen := len(buf)
	for i := 0; i < blen/2; i++ {
		buf[i], buf[blen-1-i] = buf[blen-1-i], buf[i]
	}

	return new(big.Int).SetBytes(buf)
}
Exemple #4
0
func (db *LevelDb) setBlk(sha *wire.ShaHash, blkHeight int64, buf []byte) {
	// serialize
	var lw [8]byte
	binary.LittleEndian.PutUint64(lw[0:8], uint64(blkHeight))

	shaKey := shaBlkToKey(sha)
	blkKey := int64ToKey(blkHeight)

	shaB := sha.Bytes()
	blkVal := make([]byte, len(shaB)+len(buf))
	copy(blkVal[0:], shaB)
	copy(blkVal[len(shaB):], buf)

	db.lBatch().Put(shaKey, lw[:])
	db.lBatch().Put(blkKey, blkVal)
}
Exemple #5
0
// GetTx takes a txid and returns the transaction.  If we have it.
func (ts *TxStore) GetTx(txid *wire.ShaHash) (*wire.MsgTx, error) {
	rtx := wire.NewMsgTx()

	err := ts.StateDB.View(func(btx *bolt.Tx) error {
		txns := btx.Bucket(BKTTxns)
		if txns == nil {
			return fmt.Errorf("no transactions in db")
		}
		txbytes := txns.Get(txid.Bytes())
		if txbytes == nil {
			return fmt.Errorf("tx %x not in db", txid.String())
		}
		buf := bytes.NewBuffer(txbytes)
		return rtx.Deserialize(buf)
	})
	if err != nil {
		return nil, err
	}
	return rtx, nil
}
Exemple #6
0
// UpdateAddrIndexForBlock updates the stored addrindex with passed
// index information for a particular block height. Additionally, it
// will update the stored meta-data related to the curent tip of the
// addr index. These two operations are performed in an atomic
// transaction which is commited before the function returns.
// Transactions indexed by address are stored with the following format:
//   * prefix || hash160 || blockHeight || txoffset || txlen
// Indexes are stored purely in the key, with blank data for the actual value
// in order to facilitate ease of iteration by their shared prefix and
// also to allow limiting the number of returned transactions (RPC).
// Alternatively, indexes for each address could be stored as an
// append-only list for the stored value. However, this add unnecessary
// overhead when storing and retrieving since the entire list must
// be fetched each time.
func (db *LevelDb) UpdateAddrIndexForBlock(blkSha *wire.ShaHash, blkHeight int64, addrIndex database.BlockAddrIndex) error {
	db.dbLock.Lock()
	defer db.dbLock.Unlock()

	var blankData []byte
	batch := db.lBatch()
	defer db.lbatch.Reset()

	// Write all data for the new address indexes in a single batch
	// transaction.
	for addrKey, indexes := range addrIndex {
		for _, txLoc := range indexes {
			index := &txAddrIndex{
				hash160:   addrKey,
				blkHeight: blkHeight,
				txoffset:  txLoc.TxStart,
				txlen:     txLoc.TxLen,
			}
			// The index is stored purely in the key.
			packedIndex := addrIndexToKey(index)
			batch.Put(packedIndex, blankData)
		}
	}

	// Update tip of addrindex.
	newIndexTip := make([]byte, 40, 40)
	copy(newIndexTip[:32], blkSha.Bytes())
	binary.LittleEndian.PutUint64(newIndexTip[32:], uint64(blkHeight))
	batch.Put(addrIndexMetaDataKey, newIndexTip)

	if err := db.lDb.Write(batch, db.wo); err != nil {
		return err
	}

	db.lastAddrIndexBlkIdx = blkHeight
	db.lastAddrIndexBlkSha = *blkSha

	return nil
}
Exemple #7
0
func testBasicWalletReservationWorkFlow(lnwallet *LightningWallet, t *testing.T) {
	// Create our test wallet, will have a total of 20 BTC available for
	bobNode, err := newBobNode()
	if err != nil {
		t.Fatalf("unable to create bob node: %v", err)
	}

	// Bob initiates a channel funded with 5 BTC for each side, so 10
	// BTC total. He also generates 2 BTC in change.
	fundingAmount := btcutil.Amount(5 * 1e8)
	chanReservation, err := lnwallet.InitChannelReservation(fundingAmount,
		SIGHASH, bobNode.id, 4)
	if err != nil {
		t.Fatalf("unable to initialize funding reservation: %v", err)
	}

	// The channel reservation should now be populated with a multi-sig key
	// from our HD chain, a change output with 3 BTC, and 2 outputs selected
	// of 4 BTC each. Additionally, the rest of the items needed to fufill a
	// funding contribution should also have been filled in.
	ourContribution := chanReservation.OurContribution()
	if len(ourContribution.Inputs) != 2 {
		t.Fatalf("outputs for funding tx not properly selected, have %v "+
			"outputs should have 2", len(ourContribution.Inputs))
	}
	if ourContribution.ChangeOutputs[0].Value != 3e8 {
		t.Fatalf("coin selection failed, change output should be 3e8 "+
			"satoshis, is instead %v", ourContribution.ChangeOutputs[0].Value)
	}
	if ourContribution.MultiSigKey == nil {
		t.Fatalf("alice's key for multi-sig not found")
	}
	if ourContribution.CommitKey == nil {
		t.Fatalf("alice's key for commit not found")
	}
	if ourContribution.DeliveryAddress == nil {
		t.Fatalf("alice's final delivery address not found")
	}
	if bytes.Equal(ourContribution.RevocationHash[:], zeroHash) {
		t.Fatalf("alice's revocation hash not found")
	}
	if ourContribution.CsvDelay == 0 {
		t.Fatalf("csv delay not set")
	}

	// Bob sends over his output, change addr, pub keys, initial revocation,
	// final delivery address, and his accepted csv delay for the commitmen
	// t transactions.
	if err := chanReservation.ProcessContribution(bobNode.Contribution()); err != nil {
		t.Fatalf("unable to add bob's funds to the funding tx: %v", err)
	}

	// At this point, the reservation should have our signatures, and a
	// partial funding transaction (missing bob's sigs).
	theirContribution := chanReservation.TheirContribution()
	ourFundingSigs, ourCommitSig := chanReservation.OurSignatures()
	if len(ourFundingSigs) != 2 {
		t.Fatalf("only %v of our sigs present, should have 2",
			len(ourFundingSigs))
	}
	if ourCommitSig == nil {
		t.Fatalf("commitment sig not found")
	}
	// Additionally, the funding tx should have been populated.
	if chanReservation.partialState.FundingTx == nil {
		t.Fatalf("funding transaction never created!")
	}
	// Their funds should also be filled in.
	if len(theirContribution.Inputs) != 1 {
		t.Fatalf("bob's outputs for funding tx not properly selected, have %v "+
			"outputs should have 2", len(theirContribution.Inputs))
	}
	if theirContribution.ChangeOutputs[0].Value != 2e8 {
		t.Fatalf("bob should have one change output with value 2e8"+
			"satoshis, is instead %v",
			theirContribution.ChangeOutputs[0].Value)
	}
	if theirContribution.MultiSigKey == nil {
		t.Fatalf("bob's key for multi-sig not found")
	}
	if theirContribution.CommitKey == nil {
		t.Fatalf("bob's key for commit tx not found")
	}
	if theirContribution.DeliveryAddress == nil {
		t.Fatalf("bob's final delivery address not found")
	}
	if bytes.Equal(theirContribution.RevocationHash[:], zeroHash) {
		t.Fatalf("bob's revocaiton hash not found")
	}

	// Alice responds with her output, change addr, multi-sig key and signatures.
	// Bob then responds with his signatures.
	bobsSigs, err := bobNode.signFundingTx(chanReservation.partialState.FundingTx)
	if err != nil {
		t.Fatalf("unable to sign inputs for bob: %v", err)
	}
	commitSig, err := bobNode.signCommitTx(
		chanReservation.partialState.OurCommitTx,
		chanReservation.partialState.FundingRedeemScript)
	if err != nil {
		t.Fatalf("bob is unable to sign alice's commit tx: %v", err)
	}
	if err := chanReservation.CompleteReservation(bobsSigs, commitSig); err != nil {
		t.Fatalf("unable to complete funding tx: %v", err)
	}

	// At this point, the channel can be considered "open" when the funding
	// txn hits a "comfortable" depth.

	fundingTx := chanReservation.FinalFundingTx()

	// The resulting active channel state should have been persisted to the DB.
	channel, err := lnwallet.ChannelDB.FetchOpenChannel(bobNode.id)
	if err != nil {
		t.Fatalf("unable to retrieve channel from DB: %v", err)
	}
	if channel.FundingTx.TxSha() != fundingTx.TxSha() {
		t.Fatalf("channel state not properly saved")
	}

	// The funding tx should now be valid and complete.
	// Check each input and ensure all scripts are fully valid.
	// TODO(roasbeef): remove this loop after nodetest hooked up.
	var zeroHash wire.ShaHash
	for i, input := range fundingTx.TxIn {
		var pkscript []byte
		// Bob's txin
		if bytes.Equal(input.PreviousOutPoint.Hash.Bytes(),
			zeroHash.Bytes()) {
			pkscript = bobNode.changeOutputs[0].PkScript
		} else {
			// Does the wallet know about the txin?
			txDetail, err := lnwallet.TxStore.TxDetails(&input.PreviousOutPoint.Hash)
			if txDetail == nil || err != nil {
				t.Fatalf("txstore can't find tx detail, err: %v", err)
			}
			prevIndex := input.PreviousOutPoint.Index
			pkscript = txDetail.TxRecord.MsgTx.TxOut[prevIndex].PkScript
		}

		vm, err := txscript.NewEngine(pkscript,
			fundingTx, i, txscript.StandardVerifyFlags, nil)
		if err != nil {
			// TODO(roasbeef): cancel at this stage if invalid sigs?
			t.Fatalf("cannot create script engine: %s", err)
		}
		if err = vm.Execute(); err != nil {
			t.Fatalf("cannot validate transaction: %s", err)
		}
	}
}
Exemple #8
0
// RightSha ...
func RightSha(in wire.ShaHash) wire.ShaHash {
	return wire.DoubleSha256SH(append(in.Bytes(), 0x01)) // sha(sha(in, 1))
}
Exemple #9
0
// LeftSha ...
func LeftSha(in wire.ShaHash) wire.ShaHash {
	return wire.DoubleSha256SH(in.Bytes()) // left is sha(sha(in))
}
Exemple #10
0
func toHash(txHash *wire.ShaHash) *common.Hash {
	h := new(common.Hash)
	h.SetBytes(txHash.Bytes())
	return h
}
Exemple #11
0
func shaSpentTxToKey(sha *wire.ShaHash) []byte {
	shaB := sha.Bytes()
	shaB = append(shaB, "sx"...)
	return shaB
}
Exemple #12
0
func shaBlkToKey(sha *wire.ShaHash) []byte {
	shaB := sha.Bytes()
	return shaB
}
Exemple #13
0
// AddShaHash adds the passed wire.ShaHash to the Filter.
//
// This function is safe for concurrent access.
func (bf *Filter) AddShaHash(sha *wire.ShaHash) {
	bf.mtx.Lock()
	bf.add(sha.Bytes())
	bf.mtx.Unlock()
}