Beispiel #1
0
// RegisterTransaction takes a transaction and its parents and returns a
// TransactionBuilder which can be used to expand the transaction. The most
// typical call is 'RegisterTransaction(types.Transaction{}, nil)', which
// registers a new transaction without parents.
func (w *Wallet) RegisterTransaction(t types.Transaction, parents []types.Transaction) modules.TransactionBuilder {
	// Create a deep copy of the transaction and parents by encoding them. A
	// deep copy ensures that there are no pointer or slice related errors -
	// the builder will be working directly on the transaction, and the
	// transaction may be in use elsewhere (in this case, the host is using the
	// transaction.
	pBytes := encoding.Marshal(parents)
	var pCopy []types.Transaction
	err := encoding.Unmarshal(pBytes, &pCopy)
	if err != nil {
		panic(err)
	}
	tBytes := encoding.Marshal(t)
	var tCopy types.Transaction
	err = encoding.Unmarshal(tBytes, &tCopy)
	if err != nil {
		panic(err)
	}
	return &transactionBuilder{
		parents:     pCopy,
		transaction: tCopy,

		wallet: w,
	}
}
Beispiel #2
0
// Returns the transaction with the given id
func (db *explorerDB) getTransaction(id crypto.Hash) (modules.TransactionResponse, error) {
	var tr modules.TransactionResponse

	// Look up the transaction's location
	tBytes, err := db.GetFromBucket("Transactions", encoding.Marshal(id))
	if err != nil {
		return tr, err
	}

	var tLocation txInfo
	err = encoding.Unmarshal(tBytes, &tLocation)
	if err != nil {
		return tr, err
	}

	// Look up the block specified by the location and extract the transaction
	bBytes, err := db.GetFromBucket("Blocks", encoding.Marshal(tLocation.BlockID))
	if err != nil {
		return tr, err
	}

	var block types.Block
	err = encoding.Unmarshal(bBytes, &block)
	if err != nil {
		return tr, err
	}
	tr.Tx = block.Transactions[tLocation.TxNum]
	tr.ParentID = tLocation.BlockID
	tr.TxNum = tLocation.TxNum
	tr.ResponseType = responseTransaction
	return tr, nil
}
Beispiel #3
0
// dbGetTransactionIDSet returns a 'func(*bolt.Tx) error' that decodes a
// bucket of transaction IDs into a slice. If the bucket is nil,
// dbGetTransactionIDSet returns errNotExist.
func dbGetTransactionIDSet(bucket []byte, key interface{}, ids *[]types.TransactionID) func(*bolt.Tx) error {
	return func(tx *bolt.Tx) error {
		b := tx.Bucket(bucket).Bucket(encoding.Marshal(key))
		if b == nil {
			return errNotExist
		}
		// decode into a local slice
		var txids []types.TransactionID
		err := b.ForEach(func(txid, _ []byte) error {
			var id types.TransactionID
			err := encoding.Unmarshal(txid, &id)
			if err != nil {
				return err
			}
			txids = append(txids, id)
			return nil
		})
		if err != nil {
			return err
		}
		// set pointer
		*ids = txids
		return nil
	}
}
Beispiel #4
0
// findHostAnnouncements returns a list of the host announcements found within
// a given block. No check is made to see that the ip address found in the
// announcement is actually a valid ip address.
func findHostAnnouncements(b types.Block) (announcements []modules.HostSettings) {
	for _, t := range b.Transactions {
		// the HostAnnouncement must be prefaced by the standard host
		// announcement string
		var prefix types.Specifier
		for _, arb := range t.ArbitraryData {
			copy(prefix[:], arb)
			if prefix != modules.PrefixHostAnnouncement {
				continue
			}

			// decode the HostAnnouncement
			var ha modules.HostAnnouncement
			err := encoding.Unmarshal(arb[types.SpecifierLen:], &ha)
			if err != nil {
				continue
			}

			// Add the announcement to the slice being returned.
			announcements = append(announcements, modules.HostSettings{
				NetAddress: ha.IPAddress,
			})
		}
	}

	return
}
Beispiel #5
0
// applySiacoinInputs takes all of the siacoin inputs in a transaction and
// applies them to the state, updating the diffs in the processed block.
func (cs *ConsensusSet) applySiacoinInputs(tx *bolt.Tx, pb *processedBlock, t types.Transaction) error {
	// Remove all siacoin inputs from the unspent siacoin outputs list.
	scoBucket := tx.Bucket(SiacoinOutputs)
	for _, sci := range t.SiacoinInputs {
		scoBytes := scoBucket.Get(sci.ParentID[:])
		if build.DEBUG && scoBytes == nil {
			panic(ErrMisuseApplySiacoinInput)
		}
		var sco types.SiacoinOutput
		err := encoding.Unmarshal(scoBytes, &sco)
		if err != nil {
			return err
		}
		scod := modules.SiacoinOutputDiff{
			Direction:     modules.DiffRevert,
			ID:            sci.ParentID,
			SiacoinOutput: sco,
		}
		pb.SiacoinOutputDiffs = append(pb.SiacoinOutputDiffs, scod)
		err = cs.commitBucketSiacoinOutputDiff(scoBucket, scod, modules.DiffApply)
		if err != nil {
			return err
		}
	}
	return nil
}
Beispiel #6
0
func forEachDSCO(tx *bolt.Tx, bh types.BlockHeight, fn func(id types.SiacoinOutputID, sco types.SiacoinOutput) error) error {
	bucketID := append(prefix_dsco, encoding.Marshal(bh)...)
	return forEach(tx, bucketID, func(kb, vb []byte) error {
		var key types.SiacoinOutputID
		var value types.SiacoinOutput
		err := encoding.Unmarshal(kb, &key)
		if err != nil {
			return err
		}
		err = encoding.Unmarshal(vb, &value)
		if err != nil {
			return err
		}
		return fn(key, value)
	})
}
Beispiel #7
0
// forEachSiacoinOutputs applies a function to every siacoin output and ID
func (db *setDB) forEachSiacoinOutputs(fn func(k types.SiacoinOutputID, v types.SiacoinOutput)) {
	db.forEachItem(SiacoinOutputs, func(kb, vb []byte) error {
		var key types.SiacoinOutputID
		var value types.SiacoinOutput
		err := encoding.Unmarshal(kb, &key)
		if err != nil {
			return err
		}
		err = encoding.Unmarshal(vb, &value)
		if err != nil {
			return err
		}
		fn(key, value)
		return nil
	})
}
Beispiel #8
0
// TestAnnouncement has a host announce itself to the blockchain and then
// checks that the announcement makes it correctly.
func TestAnnouncement(t *testing.T) {
	ht := CreateHostTester("TestAnnouncement", t)

	// Place the announcement.
	err := ht.host.ForceAnnounce()
	if err != nil {
		t.Fatal(err)
	}
	ht.tpUpdateWait()

	// Check that the announcement made it into the transaction pool correctly.
	txns := ht.tpool.TransactionSet()
	if len(txns) != 1 {
		t.Error("Expecting 1 transaction in transaction pool, instead there was", len(txns))
	}
	encodedAnnouncement := txns[0].ArbitraryData[0][types.SpecifierLen:]
	var ha modules.HostAnnouncement
	err = encoding.Unmarshal([]byte(encodedAnnouncement), &ha)
	if err != nil {
		t.Error(err)
	}

	// TODO: Need to check that the host announcement gets the host into the
	// hostdb.
}
Beispiel #9
0
// validSiacoins checks that the siacoin inputs and outputs are valid in the
// context of the current consensus set.
func validSiacoins(tx *bolt.Tx, t types.Transaction) error {
	scoBucket := tx.Bucket(SiacoinOutputs)
	var inputSum types.Currency
	for _, sci := range t.SiacoinInputs {
		// Check that the input spends an existing output.
		scoBytes := scoBucket.Get(sci.ParentID[:])
		if scoBytes == nil {
			return errMissingSiacoinOutput
		}

		// Check that the unlock conditions match the required unlock hash.
		var sco types.SiacoinOutput
		err := encoding.Unmarshal(scoBytes, &sco)
		if build.DEBUG && err != nil {
			panic(err)
		}
		if sci.UnlockConditions.UnlockHash() != sco.UnlockHash {
			return errWrongUnlockConditions
		}

		inputSum = inputSum.Add(sco.Value)
	}
	if inputSum.Cmp(t.SiacoinOutputSum()) != 0 {
		return errSiacoinInputOutputMismatch
	}
	return nil
}
Beispiel #10
0
// GetHashInfo returns sufficient data about the hash that was
// provided to do more extensive lookups
func (e *Explorer) GetHashInfo(hash []byte) (interface{}, error) {
	if len(hash) < crypto.HashSize {
		return nil, errors.New("requested hash not long enough")
	}

	lockID := e.mu.RLock()
	defer e.mu.RUnlock(lockID)

	// Perform a lookup to tell which type of hash it is
	typeBytes, err := e.db.GetFromBucket("Hashes", hash[:crypto.HashSize])
	if err != nil {
		return nil, err
	}

	var hashType int
	err = encoding.Unmarshal(typeBytes, &hashType)
	if err != nil {
		return nil, err
	}

	switch hashType {
	case hashBlock:
		var id types.BlockID
		copy(id[:], hash[:])
		return e.db.getBlock(types.BlockID(id))
	case hashTransaction:
		var id crypto.Hash
		copy(id[:], hash[:])
		return e.db.getTransaction(id)
	case hashFilecontract:
		var id types.FileContractID
		copy(id[:], hash[:])
		return e.db.getFileContract(id)
	case hashCoinOutputID:
		var id types.SiacoinOutputID
		copy(id[:], hash[:])
		return e.db.getSiacoinOutput(id)
	case hashFundOutputID:
		var id types.SiafundOutputID
		copy(id[:], hash[:])
		return e.db.getSiafundOutput(id)
	case hashUnlockHash:
		// Check that the address is valid before doing a lookup
		if len(hash) != crypto.HashSize+types.UnlockHashChecksumSize {
			return nil, errors.New("address does not have a valid checksum")
		}
		var id types.UnlockHash
		copy(id[:], hash[:crypto.HashSize])
		uhChecksum := crypto.HashObject(id)

		givenChecksum := hash[crypto.HashSize : crypto.HashSize+types.UnlockHashChecksumSize]
		if !bytes.Equal(givenChecksum, uhChecksum[:types.UnlockHashChecksumSize]) {
			return nil, errors.New("address does not have a valid checksum")
		}

		return e.db.getAddressTransactions(id)
	default:
		return nil, errors.New("bad hash type")
	}
}
Beispiel #11
0
Datei: update.go Projekt: mm3/Sia
// findHostAnnouncements returns a list of the host announcements found within
// a given block. No check is made to see that the ip address found in the
// announcement is actually a valid ip address.
func findHostAnnouncements(b types.Block) (announcements []modules.HostSettings) {
	for _, t := range b.Transactions {
		for _, data := range t.ArbitraryData {
			// the HostAnnouncement must be prefaced by the standard host announcement string
			if !strings.HasPrefix(data, modules.PrefixHostAnnouncement) {
				continue
			}

			// decode the HostAnnouncement
			var ha modules.HostAnnouncement
			encAnnouncement := []byte(strings.TrimPrefix(data, modules.PrefixHostAnnouncement))
			err := encoding.Unmarshal(encAnnouncement, &ha)
			if err != nil {
				continue
			}

			// Add the announcement to the slice being returned.
			announcements = append(announcements, modules.HostSettings{
				IPAddress: ha.IPAddress,
			})
		}
	}

	return
}
Beispiel #12
0
// EarliestChildTimestamp returns the earliest timestamp that the next block can
// have in order for it to be considered valid.
func (cs *ConsensusSet) EarliestChildTimestamp(bid types.BlockID) (timestamp types.Timestamp, exists bool) {
	// Lock is not needed because the values being read will not change once
	// they have been created.
	err := cs.db.View(func(tx *bolt.Tx) error {
		// Check that the parent exists.
		blockMap := tx.Bucket(BlockMap)

		// The identifier for the BlockMap is the sia encoding of the parent
		// id. The sia encoding is the same as ParentID[:].
		var parent processedBlock
		parentBytes := blockMap.Get(bid[:])
		if parentBytes == nil {
			return ErrOrphan
		}
		err := encoding.Unmarshal(parentBytes, &parent)
		if err != nil {
			return err
		}
		timestamp = earliestChildTimestamp(blockMap, &parent)
		return nil
	})
	if err != nil {
		return 0, false
	}
	return timestamp, true
}
Beispiel #13
0
// forEachFileContracts applies a function to each (file contract id, filecontract)
// pair in the consensus set
func (db *setDB) forEachFileContracts(fn func(k types.FileContractID, v types.FileContract)) {
	db.forEachItem(FileContracts, func(kb, vb []byte) error {
		var key types.FileContractID
		var value types.FileContract
		err := encoding.Unmarshal(kb, &key)
		if err != nil {
			return err
		}
		err = encoding.Unmarshal(vb, &value)
		if err != nil {
			return err
		}
		fn(key, value)
		return nil
	})
}
Beispiel #14
0
// initUnseededKeys loads all of the unseeded keys into the wallet after the
// wallet gets unlocked.
func (w *Wallet) initUnseededKeys(masterKey crypto.TwofishKey) error {
	for _, uk := range w.persist.UnseededKeys {
		// Verify that the decryption key is correct.
		encKey := uidEncryptionKey(masterKey, uk.UID)
		expectedDecryptedVerification := make([]byte, crypto.EntropySize)
		decryptedVerification, err := encKey.DecryptBytes(uk.EncryptionVerification)
		if err != nil {
			return err
		}
		if !bytes.Equal(expectedDecryptedVerification, decryptedVerification) {
			return modules.ErrBadEncryptionKey
		}

		// Decrypt the spendable key and add it to the wallet.
		encodedKey, err := encKey.DecryptBytes(uk.SpendableKey)
		if err != nil {
			return err
		}
		var sk spendableKey
		err = encoding.Unmarshal(encodedKey, &sk)
		if err != nil {
			return err
		}
		w.keys[sk.UnlockConditions.UnlockHash()] = sk
	}
	return nil
}
Beispiel #15
0
// Returns an array of block summaries. Bounds checking should be done elsewhere
func (db *explorerDB) dbBlockSummaries(start types.BlockHeight, finish types.BlockHeight) ([]modules.ExplorerBlockData, error) {
	summaries := make([]modules.ExplorerBlockData, int(finish-start))
	err := db.View(func(tx *bolt.Tx) error {
		heights := tx.Bucket([]byte("Heights"))

		// Iterate over each block height, constructing a
		// summary data structure for each block
		for i := start; i < finish; i++ {
			bSummaryBytes := heights.Get(encoding.Marshal(i))
			if bSummaryBytes == nil {
				return errors.New("Block not found in height bucket")
			}

			err := encoding.Unmarshal(bSummaryBytes, &summaries[i-start])
			if err != nil {
				return err
			}
		}
		return nil
	})
	if err != nil {
		return nil, err
	}
	return summaries, nil
}
Beispiel #16
0
// inconsistencyDetected indicates whether inconsistency has been detected
// within the database.
func inconsistencyDetected(tx *bolt.Tx) (detected bool) {
	inconsistencyBytes := tx.Bucket(Consistency).Get(Consistency)
	err := encoding.Unmarshal(inconsistencyBytes, &detected)
	if build.DEBUG && err != nil {
		panic(err)
	}
	return
}
Beispiel #17
0
// forEachDelayedSiacoinOutputsHeight applies a function to every siacoin output at a given height
func (db *setDB) forEachDelayedSiacoinOutputsHeight(h types.BlockHeight, fn func(k types.SiacoinOutputID, v types.SiacoinOutput)) {
	bucketID := append(prefix_dsco, encoding.Marshal(h)...)
	db.forEachItem(bucketID, func(kb, vb []byte) error {
		var key types.SiacoinOutputID
		var value types.SiacoinOutput
		err := encoding.Unmarshal(kb, &key)
		if err != nil {
			return err
		}
		err = encoding.Unmarshal(vb, &value)
		if err != nil {
			return err
		}
		fn(key, value)
		return nil
	})
}
Beispiel #18
0
// dbGetAndDecode returns a 'func(*bolt.Tx) error' that retrieves and decodes
// a value from the specified bucket. If the value does not exist,
// dbGetAndDecode returns errNotExist.
func dbGetAndDecode(bucket []byte, key, val interface{}) func(*bolt.Tx) error {
	return func(tx *bolt.Tx) error {
		valBytes := tx.Bucket(bucket).Get(encoding.Marshal(key))
		if valBytes == nil {
			return errNotExist
		}
		return encoding.Unmarshal(valBytes, val)
	}
}
Beispiel #19
0
// blockHeight returns the height of the blockchain.
func blockHeight(tx *bolt.Tx) types.BlockHeight {
	var height types.BlockHeight
	bh := tx.Bucket(BlockHeight)
	err := encoding.Unmarshal(bh.Get(BlockHeight), &height)
	if build.DEBUG && err != nil {
		panic(err)
	}
	return height
}
Beispiel #20
0
// TestUnitSignatureEncoding creates and encodes a public key, and verifies
// that it decodes correctly, does the same with a signature.
func TestUnitSignatureEncoding(t *testing.T) {
	// Create a dummy key pair.
	var sk SecretKey
	sk[0] = 4
	sk[32] = 5
	pk := sk.PublicKey()

	// Marshal and unmarshal the public key.
	marshalledPK := encoding.Marshal(pk)
	var unmarshalledPK PublicKey
	err := encoding.Unmarshal(marshalledPK, &unmarshalledPK)
	if err != nil {
		t.Fatal(err)
	}

	// Test the public keys for equality.
	if pk != unmarshalledPK {
		t.Error("pubkey not the same after marshalling and unmarshalling")
	}

	// Create a signature using the secret key.
	var signedData Hash
	rand.Read(signedData[:])
	sig, err := SignHash(signedData, sk)
	if err != nil {
		t.Fatal(err)
	}

	// Marshal and unmarshal the signature.
	marshalledSig := encoding.Marshal(sig)
	var unmarshalledSig Signature
	err = encoding.Unmarshal(marshalledSig, &unmarshalledSig)
	if err != nil {
		t.Fatal(err)
	}

	// Test signatures for equality.
	if sig != unmarshalledSig {
		t.Error("signature not same after marshalling and unmarshalling")
	}

}
Beispiel #21
0
// getPath returns the block id at 'height' in the block path.
func getPath(tx *bolt.Tx, height types.BlockHeight) (id types.BlockID) {
	idBytes, err := getItem(tx, BlockPath, height)
	if build.DEBUG && err != nil {
		panic(err)
	}
	err = encoding.Unmarshal(idBytes, &id)
	if build.DEBUG && err != nil {
		panic(err)
	}
	return id
}
Beispiel #22
0
// BenchmarkDecodeEmptyBlock benchmarks decoding an empty block.
//
// i7-4770,  b0b162d: 38 MB/s
// i5-4670K, 9a90f86: 55 MB/s
func BenchmarkDecodeEmptyBlock(b *testing.B) {
	var block Block
	encodedBlock := encoding.Marshal(block)
	b.SetBytes(int64(len(encodedBlock)))
	for i := 0; i < b.N; i++ {
		err := encoding.Unmarshal(encodedBlock, &block)
		if err != nil {
			b.Fatal(err)
		}
	}
}
Beispiel #23
0
func forEachFCExpiration(tx *bolt.Tx, bh types.BlockHeight, fn func(types.FileContractID) error) error {
	bucketID := append(prefix_fcex, encoding.Marshal(bh)...)
	return forEach(tx, bucketID, func(kb, bv []byte) error {
		var id types.FileContractID
		err := encoding.Unmarshal(kb, &id)
		if err != nil {
			return err
		}
		return fn(id)
	})
}
Beispiel #24
0
// getFileContract fetches a file contract from the database, returning an
// error if it is not there.
func getFileContract(tx *bolt.Tx, id types.FileContractID) (fc types.FileContract, err error) {
	fcBytes := tx.Bucket(FileContracts).Get(id[:])
	if fcBytes == nil {
		return types.FileContract{}, errNilItem
	}
	err = encoding.Unmarshal(fcBytes, &fc)
	if err != nil {
		return types.FileContract{}, err
	}
	return fc, nil
}
Beispiel #25
0
func getFileContract(tx *bolt.Tx, id types.FileContractID) (fc types.FileContract, err error) {
	fcBytes, err := getItem(tx, FileContracts, id)
	if err != nil {
		return types.FileContract{}, err
	}
	err = encoding.Unmarshal(fcBytes, &fc)
	if err != nil {
		return types.FileContract{}, err
	}
	return fc, nil
}
Beispiel #26
0
// getPath retreives the block id of a block at a given hegiht from the path
//
// DEPRECATED
func (db *setDB) getPath(h types.BlockHeight) (id types.BlockID) {
	idBytes, err := db.getItem(BlockPath, h)
	if err != nil {
		panic(err)
	}
	err = encoding.Unmarshal(idBytes, &id)
	if err != nil {
		panic(err)
	}
	return
}
Beispiel #27
0
// getSiafundPool returns the current value of the siafund pool. No error is
// returned as the siafund pool should always be available.
func getSiafundPool(tx *bolt.Tx) (pool types.Currency) {
	bucket := tx.Bucket(SiafundPool)
	poolBytes := bucket.Get(SiafundPool)
	// An error should only be returned if the object stored in the siafund
	// pool bucket is either unavailable or otherwise malformed. As this is a
	// developer error, a panic is appropriate.
	err := encoding.Unmarshal(poolBytes, &pool)
	if build.DEBUG && err != nil {
		panic(err)
	}
	return pool
}
Beispiel #28
0
// TestCurrencyEncoding checks that a currency can encode and decode without
// error.
func TestCurrencyEncoding(t *testing.T) {
	c := NewCurrency64(351)
	cMar := encoding.Marshal(c)
	var cUmar Currency
	err := encoding.Unmarshal(cMar, &cUmar)
	if err != nil {
		t.Error("Error unmarshalling a currency:", err)
	}
	if cUmar.Cmp(c) != 0 {
		t.Error("Marshalling and Unmarshalling a currency did not work correctly")
	}
}
Beispiel #29
0
// getPath returns the block id at 'height' in the block path.
func getPath(tx *bolt.Tx, height types.BlockHeight) (id types.BlockID, err error) {
	idBytes := tx.Bucket(BlockPath).Get(encoding.Marshal(height))
	if idBytes == nil {
		return types.BlockID{}, errNilItem
	}

	err = encoding.Unmarshal(idBytes, &id)
	if build.DEBUG && err != nil {
		panic(err)
	}
	return id, nil
}
Beispiel #30
0
// getSiafundOutput fetches a siafund output from the database. An error is
// returned if the siafund output does not exist.
func getSiafundOutput(tx *bolt.Tx, id types.SiafundOutputID) (types.SiafundOutput, error) {
	sfoBytes := tx.Bucket(SiafundOutputs).Get(id[:])
	if sfoBytes == nil {
		return types.SiafundOutput{}, errNilItem
	}
	var sfo types.SiafundOutput
	err := encoding.Unmarshal(sfoBytes, &sfo)
	if err != nil {
		return types.SiafundOutput{}, err
	}
	return sfo, nil
}