Example #1
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
}
Example #2
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,
	}
}
Example #3
0
// addFileContract adds a file contract to the database. An error is returned
// if the file contract is already in the database.
func addFileContract(tx *bolt.Tx, id types.FileContractID, fc types.FileContract) {
	// Add the file contract to the database.
	fcBucket := tx.Bucket(FileContracts)
	// Sanity check - should not be adding a zero-payout file contract.
	if build.DEBUG && fc.Payout.IsZero() {
		panic("adding zero-payout file contract")
	}
	// Sanity check - should not be adding a file contract already in the db.
	if build.DEBUG && fcBucket.Get(id[:]) != nil {
		panic("repeat file contract")
	}
	err := fcBucket.Put(id[:], encoding.Marshal(fc))
	if build.DEBUG && err != nil {
		panic(err)
	}

	// Add an entry for when the file contract expires.
	expirationBucketID := append(prefixFCEX, encoding.Marshal(fc.WindowEnd)...)
	expirationBucket, err := tx.CreateBucketIfNotExists(expirationBucketID)
	if build.DEBUG && err != nil {
		panic(err)
	}
	err = expirationBucket.Put(id[:], []byte{})
	if build.DEBUG && err != nil {
		panic(err)
	}
}
Example #4
0
// newChild creates a blockNode from a block and adds it to the parent's set of
// children. The new node is also returned. It necessairly modifies the database
//
// TODO: newChild has a fair amount of room for optimization.
func (cs *ConsensusSet) newChild(pb *processedBlock, b types.Block) *processedBlock {
	// Create the child node.
	childID := b.ID()
	child := &processedBlock{
		Block:  b,
		Parent: b.ParentID,

		Height: pb.Height + 1,
		Depth:  pb.childDepth(),
	}
	err := cs.db.Update(func(tx *bolt.Tx) error {
		blockMap := tx.Bucket(BlockMap)
		err := cs.setChildTarget(blockMap, child)
		if err != nil {
			return err
		}
		pb.Children = append(pb.Children, childID)
		err = blockMap.Put(child.Block.ParentID[:], encoding.Marshal(*pb))
		if err != nil {
			return err
		}
		return blockMap.Put(childID[:], encoding.Marshal(*child))
	})
	if build.DEBUG && err != nil {
		panic(err)
	}
	return child
}
Example #5
0
// BenchmarkEncodeEmptyBlock benchmarks encoding an empty block.
//
// i5-4670K, 9a90f86: 48 MB/s
func BenchmarkEncodeBlock(b *testing.B) {
	var block Block
	b.SetBytes(int64(len(encoding.Marshal(block))))
	for i := 0; i < b.N; i++ {
		encoding.Marshal(block)
	}
}
Example #6
0
// createDSCOBucket creates a bucket for the delayed siacoin outputs at the
// input height.
func createDSCOBucket(tx *bolt.Tx, bh types.BlockHeight) error {
	bucketID := append(prefix_dsco, encoding.Marshal(bh)...)
	dscoBuckets := tx.Bucket(DSCOBuckets)
	err := dscoBuckets.Put(encoding.Marshal(bh), encoding.Marshal(bucketID))
	if err != nil {
		panic(err)
	}
	_, err = tx.CreateBucket(bucketID)
	return err
}
Example #7
0
// SigHash returns the hash of the fields in a transaction covered by a given
// signature. See CoveredFields for more details.
func (t Transaction) SigHash(i int) crypto.Hash {
	cf := t.TransactionSignatures[i].CoveredFields
	var signedData []byte
	if cf.WholeTransaction {
		signedData = encoding.MarshalAll(
			t.SiacoinInputs,
			t.SiacoinOutputs,
			t.FileContracts,
			t.FileContractRevisions,
			t.StorageProofs,
			t.SiafundInputs,
			t.SiafundOutputs,
			t.MinerFees,
			t.ArbitraryData,
			t.TransactionSignatures[i].ParentID,
			t.TransactionSignatures[i].PublicKeyIndex,
			t.TransactionSignatures[i].Timelock,
		)
	} else {
		for _, input := range cf.SiacoinInputs {
			signedData = append(signedData, encoding.Marshal(t.SiacoinInputs[input])...)
		}
		for _, output := range cf.SiacoinOutputs {
			signedData = append(signedData, encoding.Marshal(t.SiacoinOutputs[output])...)
		}
		for _, contract := range cf.FileContracts {
			signedData = append(signedData, encoding.Marshal(t.FileContracts[contract])...)
		}
		for _, revision := range cf.FileContractRevisions {
			signedData = append(signedData, encoding.Marshal(t.FileContractRevisions[revision])...)
		}
		for _, storageProof := range cf.StorageProofs {
			signedData = append(signedData, encoding.Marshal(t.StorageProofs[storageProof])...)
		}
		for _, siafundInput := range cf.SiafundInputs {
			signedData = append(signedData, encoding.Marshal(t.SiafundInputs[siafundInput])...)
		}
		for _, siafundOutput := range cf.SiafundOutputs {
			signedData = append(signedData, encoding.Marshal(t.SiafundOutputs[siafundOutput])...)
		}
		for _, minerFee := range cf.MinerFees {
			signedData = append(signedData, encoding.Marshal(t.MinerFees[minerFee])...)
		}
		for _, arbData := range cf.ArbitraryData {
			signedData = append(signedData, encoding.Marshal(t.ArbitraryData[arbData])...)
		}
	}

	for _, sig := range cf.TransactionSignatures {
		signedData = append(signedData, encoding.Marshal(t.TransactionSignatures[sig])...)
	}

	return crypto.HashBytes(signedData)
}
Example #8
0
// insertItem inserts an item to a bucket. In debug mode, a panic is thrown if
// the bucket does not exist or if the item is already in the bucket.
func insertItem(tx *bolt.Tx, bucket []byte, key, value interface{}) error {
	b := tx.Bucket(bucket)
	if build.DEBUG && b == nil {
		panic(errNilBucket)
	}
	k := encoding.Marshal(key)
	v := encoding.Marshal(value)
	if build.DEBUG && b.Get(k) != nil {
		panic(errRepeatInsert)
	}
	return b.Put(k, v)
}
Example #9
0
func (tx *boltTx) putObject(bucket string, key, val interface{}) {
	// if an error has already be encountered, do nothing
	if tx.err != nil {
		return
	}

	b := tx.Bucket([]byte(bucket))
	if b == nil {
		tx.err = errors.New("bucket does not exist: " + bucket)
		return
	}
	tx.err = b.Put(encoding.Marshal(key), encoding.Marshal(val))
	return
}
// BenchmarkStandaloneValid times how long it takes to verify a single
// large transaction, with a certain number of signatures
func BenchmarkStandaloneValid(b *testing.B) {
	numSigs := 7
	// make a transaction numSigs with valid inputs with valid signatures
	b.ReportAllocs()
	txn := Transaction{}
	sk := make([]crypto.SecretKey, numSigs)
	pk := make([]crypto.PublicKey, numSigs)
	for i := 0; i < numSigs; i++ {
		s, p, err := crypto.GenerateKeyPair()
		if err != nil {
			b.Fatal(err)
		}
		sk[i] = s
		pk[i] = p

		uc := UnlockConditions{
			PublicKeys: []SiaPublicKey{
				{Algorithm: SignatureEd25519, Key: pk[i][:]},
			},
			SignaturesRequired: 1,
		}
		txn.SiacoinInputs = append(txn.SiacoinInputs, SiacoinInput{
			UnlockConditions: uc,
		})
		copy(txn.SiacoinInputs[i].ParentID[:], encoding.Marshal(i))
		txn.TransactionSignatures = append(txn.TransactionSignatures, TransactionSignature{
			CoveredFields: CoveredFields{WholeTransaction: true},
		})
		copy(txn.TransactionSignatures[i].ParentID[:], encoding.Marshal(i))
	}
	// Transaction must be constructed before signing
	for i := 0; i < numSigs; i++ {
		sigHash := txn.SigHash(i)
		sig0, err := crypto.SignHash(sigHash, sk[i])
		if err != nil {
			b.Fatal(err)
		}
		txn.TransactionSignatures[i].Signature = sig0[:]
	}

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		err := txn.StandaloneValid(10)
		if err != nil {
			b.Fatal(err)
		}
	}
}
Example #11
0
// setSiafundPool updates the saved siafund pool on disk
func setSiafundPool(tx *bolt.Tx, c types.Currency) {
	bucket := tx.Bucket(SiafundPool)
	err := bucket.Put(SiafundPool, encoding.Marshal(c))
	if build.DEBUG && err != nil {
		panic(err)
	}
}
Example #12
0
// applyFileContractMaintenance looks for all of the file contracts that have
// expired without an appropriate storage proof, and calls 'applyMissedProof'
// for the file contract.
func applyFileContractMaintenance(tx *bolt.Tx, pb *processedBlock) {
	// Get the bucket pointing to all of the expiring file contracts.
	fceBucketID := append(prefixFCEX, encoding.Marshal(pb.Height)...)
	fceBucket := tx.Bucket(fceBucketID)
	// Finish if there are no expiring file contracts.
	if fceBucket == nil {
		return
	}

	var dscods []modules.DelayedSiacoinOutputDiff
	var fcds []modules.FileContractDiff
	err := fceBucket.ForEach(func(keyBytes, valBytes []byte) error {
		var id types.FileContractID
		copy(id[:], keyBytes)
		amspDSCODS, fcd := applyMissedStorageProof(tx, pb, id)
		fcds = append(fcds, fcd)
		dscods = append(dscods, amspDSCODS...)
		return nil
	})
	if build.DEBUG && err != nil {
		panic(err)
	}
	for _, dscod := range dscods {
		pb.DelayedSiacoinOutputDiffs = append(pb.DelayedSiacoinOutputDiffs, dscod)
		commitDelayedSiacoinOutputDiff(tx, dscod, modules.DiffApply)
	}
	for _, fcd := range fcds {
		pb.FileContractDiffs = append(pb.FileContractDiffs, fcd)
		commitFileContractDiff(tx, fcd, modules.DiffApply)
	}
	err = tx.DeleteBucket(fceBucketID)
	if build.DEBUG && err != nil {
		panic(err)
	}
}
Example #13
0
func TestLowFeeTransaction(t *testing.T) {
	if testing.Short() {
		t.SkipNow()
	}

	// Initialize variables to populate transaction pool
	tpt := newTpoolTester("TestLowFeeTransaction", t)
	emptyData := make([]byte, 15e3-16)
	randData := make([]byte, 16) // not yet random
	emptyTxn := types.Transaction{
		ArbitraryData: []string{"NonSia" + string(append(emptyData, randData...))},
	}
	transSize := len(encoding.Marshal(emptyTxn))

	// Fill it to 20 MB
	for i := 0; i <= (TransactionPoolSizeForFee / transSize); i++ {
		// Make a unique transaction to accept
		rand.Read(randData)
		uniqueTxn := types.Transaction{
			ArbitraryData: []string{"NonSia" + string(append(emptyData, randData...))},
		}

		// Accept said transaction
		err := tpt.tpool.AcceptTransaction(uniqueTxn)
		if err != nil {
			t.Error(err)
		}
	}

	// Should be the straw to break the camel's back (i.e. the transaction at >20 MB)
	err := tpt.tpool.AcceptTransaction(emptyTxn)
	if err != ErrLowMinerFees {
		t.Fatal("expecting ErrLowMinerFees got:", err)
	}
}
Example #14
0
// createDSCOBucket creates a bucket for the delayed siacoin outputs at the
// input height.
func createDSCOBucket(tx *bolt.Tx, bh types.BlockHeight) {
	bucketID := append(prefixDSCO, encoding.Marshal(bh)...)
	_, err := tx.CreateBucket(bucketID)
	if build.DEBUG && err != nil {
		panic(err)
	}
}
Example #15
0
// TestFindHostAnnouncements probes the findHostAnnouncements function
func TestFindHostAnnouncements(t *testing.T) {
	// Create a block with a host announcement.
	announcement := modules.PrefixHostAnnouncement + string(encoding.Marshal(modules.HostAnnouncement{}))
	b := types.Block{
		Transactions: []types.Transaction{
			types.Transaction{
				ArbitraryData: []string{announcement},
			},
		},
	}
	announcements := findHostAnnouncements(b)
	if len(announcements) != 1 {
		t.Error("host announcement not found in block")
	}

	// Try with an altered prefix
	b.Transactions[0].ArbitraryData[0] = "bad" + b.Transactions[0].ArbitraryData[0]
	announcements = findHostAnnouncements(b)
	if len(announcements) != 0 {
		t.Error("host announcement found when there was an invalid prefix")
	}

	// Try with an invalid host encoding.
	b.Transactions[0].ArbitraryData[0] = modules.PrefixHostAnnouncement + "bad"
	announcements = findHostAnnouncements(b)
	if len(announcements) != 0 {
		t.Error("host announcement found when there was an invalid encoding of a host announcement")
	}
}
Example #16
0
// addBlockMap adds a processed block to the block map.
func addBlockMap(tx *bolt.Tx, pb *processedBlock) {
	id := pb.Block.ID()
	err := tx.Bucket(BlockMap).Put(id[:], encoding.Marshal(*pb))
	if build.DEBUG && err != nil {
		panic(err)
	}
}
Example #17
0
// BenchmarkAddBlockMap benchmarks adding many blocks to the set database
func BenchmarkAddBlockMap(b *testing.B) {
	b.ReportAllocs()
	cst, err := createConsensusSetTester("BenchmarkAddBlockMap")
	if err != nil {
		b.Fatal(err)
	}

	// create a bunch of blocks to be added
	blocks := make([]processedBlock, b.N)
	var nonce types.BlockNonce
	for i := 0; i < b.N; i++ {
		nonceBytes := encoding.Marshal(i)
		copy(nonce[:], nonceBytes[:8])
		blocks[i] = processedBlock{
			Block: types.Block{
				Nonce: nonce,
			},
		}
	}

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		cst.cs.db.addBlockMap(&blocks[i])
	}
}
Example #18
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
}
Example #19
0
func addSiacoinOutput(tx *bolt.Tx, id types.SiacoinOutputID, sco types.SiacoinOutput) error {
	siacoinOutputs := tx.Bucket(SiacoinOutputs)
	if build.DEBUG && siacoinOutputs.Get(id[:]) != nil {
		panic(errRepeatInsert)
	}
	return siacoinOutputs.Put(id[:], encoding.Marshal(sco))
}
Example #20
0
// Broadcast calls an RPC on all of the peers in the Gateway's peer list. The
// calls are run in parallel. Broadcasts are restricted to "one-way" RPCs,
// which simply write an object and disconnect. This is why Broadcast takes an
// interface{} instead of an RPCFunc.
func (g *Gateway) Broadcast(name string, obj interface{}) {
	peers := g.Peers()
	g.log.Printf("INFO: broadcasting RPC \"%v\" to %v peers", name, len(peers))

	// only encode obj once, instead of using WriteObject
	enc := encoding.Marshal(obj)
	fn := func(conn modules.PeerConn) error {
		return encoding.WritePrefix(conn, enc)
	}

	var wg sync.WaitGroup
	wg.Add(len(peers))
	for _, addr := range peers {
		go func(addr modules.NetAddress) {
			err := g.RPC(addr, name, fn)
			if err != nil {
				// try one more time before giving up
				time.Sleep(10 * time.Second)
				g.RPC(addr, name, fn)
			}
			wg.Done()
		}(addr)
	}
	wg.Wait()
}
Example #21
0
// ReceiveUpdatedUnconfirmedTransactions will replace the current unconfirmed
// set of transactions with the input transactions.
func (m *Miner) ReceiveUpdatedUnconfirmedTransactions(unconfirmedTransactions []types.Transaction, _ modules.ConsensusChange) {
	if err := m.tg.Add(); err != nil {
		return
	}
	defer m.tg.Done()

	m.mu.Lock()
	defer m.mu.Unlock()

	// Edge case - if there are no transactions, set the block's transactions
	// to nil and return.
	if len(unconfirmedTransactions) == 0 {
		m.persist.UnsolvedBlock.Transactions = nil
		return
	}

	// Add transactions to the block until the block size limit is reached.
	// Transactions are assumed to be in a sensible order.
	var i int
	remainingSize := int(types.BlockSizeLimit - 5e3)
	for i = range unconfirmedTransactions {
		remainingSize -= len(encoding.Marshal(unconfirmedTransactions[i]))
		if remainingSize < 0 {
			break
		}
	}
	m.persist.UnsolvedBlock.Transactions = unconfirmedTransactions[:i+1]
}
Example #22
0
// announce creates an announcement transaction and submits it to the network.
func (h *Host) announce(addr modules.NetAddress) error {
	// create the transaction that will hold the announcement
	var t types.Transaction
	id, err := h.wallet.RegisterTransaction(t)
	if err != nil {
		return err
	}

	// create and encode the announcement and add it to the arbitrary data of
	// the transaction.
	announcement := encoding.Marshal(modules.HostAnnouncement{
		IPAddress: addr,
	})
	_, _, err = h.wallet.AddArbitraryData(id, append(modules.PrefixHostAnnouncement[:], announcement...))
	if err != nil {
		return err
	}
	t, err = h.wallet.SignTransaction(id, true)
	if err != nil {
		return err
	}

	// Add the transaction to the transaction pool.
	err = h.tpool.AcceptTransaction(t)
	if err == modules.ErrTransactionPoolDuplicate {
		return errors.New("you have already announced yourself")
	}
	if err != nil {
		return err
	}

	return nil
}
Example #23
0
// inBucket checks if an item with the given key is in the bucket
func (db *setDB) inBucket(bucket []byte, key interface{}) bool {
	exists, err := db.Exists(bucket, encoding.Marshal(key))
	if build.DEBUG && err != nil {
		panic(err)
	}
	return exists
}
Example #24
0
// IsStandardTransaction enforces extra rules such as a transaction size limit.
// These rules can be altered without disrupting consensus.
func (tp *TransactionPool) IsStandardTransaction(t types.Transaction) error {
	// Check that the size of the transaction does not exceed the standard
	// established in Standard.md. Larger transactions are a DOS vector,
	// because someone can fill a large transaction with a bunch of signatures
	// that require hashing the entire transaction. Several hundred megabytes
	// of hashing can be required of a verifier. Enforcing this rule makes it
	// more difficult for attackers to exploid this DOS vector, though a miner
	// with sufficient power could still create unfriendly blocks.
	if len(encoding.Marshal(t)) > modules.TransactionSizeLimit {
		return modules.ErrLargeTransaction
	}

	// Check that all public keys are of a recognized type. Need to check all
	// of the UnlockConditions, which currently can appear in 3 separate fields
	// of the transaction. Unrecognized types are ignored because a softfork
	// may make certain unrecognized signatures invalid, and this node cannot
	// tell which sigantures are the invalid ones.
	for _, sci := range t.SiacoinInputs {
		err := tp.checkUnlockConditions(sci.UnlockConditions)
		if err != nil {
			return err
		}
	}
	for _, fcr := range t.FileContractRevisions {
		err := tp.checkUnlockConditions(fcr.UnlockConditions)
		if err != nil {
			return err
		}
	}
	for _, sfi := range t.SiafundInputs {
		err := tp.checkUnlockConditions(sfi.UnlockConditions)
		if err != nil {
			return err
		}
	}

	// Check that all arbitrary data is prefixed using the recognized set of
	// prefixes. The allowed prefixes include a 'NonSia' prefix for truly
	// arbitrary data. Blocking all other prefixes allows arbitrary data to be
	// used to orchestrate more complicated soft forks in the future without
	// putting older nodes at risk of violating the new rules.
	var prefix types.Specifier
	for _, arb := range t.ArbitraryData {
		// Check for a whilelisted prefix.
		copy(prefix[:], arb)
		if prefix == modules.PrefixHostAnnouncement ||
			prefix == modules.PrefixNonSia {
			continue
		}

		// COMPATv0.3.3.3 - deprecated whitelisted prefixes.
		strData := string(arb)
		if strings.HasPrefix(strData, modules.PrefixStrNonSia) {
			continue
		}

		return modules.ErrInvalidArbPrefix
	}
	return nil
}
Example #25
0
// acceptTransactionSet verifies that a transaction set is allowed to be in the
// transaction pool, and then adds it to the transaction pool.
func (tp *TransactionPool) acceptTransactionSet(ts []types.Transaction) error {
	if len(ts) == 0 {
		return errEmptySet
	}

	// Remove all transactions that have been confirmed in the transaction set.
	err := tp.db.Update(func(tx *bolt.Tx) error {
		oldTS := ts
		ts = []types.Transaction{}
		for _, txn := range oldTS {
			if !tp.transactionConfirmed(tx, txn.ID()) {
				ts = append(ts, txn)
			}
		}
		return nil
	})
	if err != nil {
		return err
	}
	// If no transactions remain, return a dublicate error.
	if len(ts) == 0 {
		return modules.ErrDuplicateTransactionSet
	}

	// Check the composition of the transaction set, including fees and
	// IsStandard rules.
	err = tp.checkTransactionSetComposition(ts)
	if err != nil {
		return err
	}

	// Check for conflicts with other transactions, which would indicate a
	// double-spend. Legal children of a transaction set will also trigger the
	// conflict-detector.
	oids := relatedObjectIDs(ts)
	var conflicts []TransactionSetID
	for _, oid := range oids {
		conflict, exists := tp.knownObjects[oid]
		if exists {
			conflicts = append(conflicts, conflict)
		}
	}
	if len(conflicts) > 0 {
		return tp.handleConflicts(ts, conflicts)
	}
	cc, err := tp.consensusSet.TryTransactionSet(ts)
	if err != nil {
		return modules.NewConsensusConflict(err.Error())
	}

	// Add the transaction set to the pool.
	setID := TransactionSetID(crypto.HashObject(ts))
	tp.transactionSets[setID] = ts
	for _, oid := range oids {
		tp.knownObjects[oid] = setID
	}
	tp.transactionSetDiffs[setID] = cc
	tp.transactionListSize += len(encoding.Marshal(ts))
	return nil
}
Example #26
0
func BenchmarkGetBlockMap(b *testing.B) {
	b.ReportAllocs()
	cst, err := createConsensusSetTester("BenchmarkGetBlockMap")
	if err != nil {
		b.Fatal(err)
	}

	// create a bunch of blocks to be added
	blocks := make([]processedBlock, 100)
	blockIDs := make([]types.BlockID, 100)
	var nonce types.BlockNonce
	for i := 0; i < 100; i++ {
		nonceBytes := encoding.Marshal(i)
		copy(nonce[:], nonceBytes[:8])
		blocks[i] = processedBlock{
			Block: types.Block{
				Nonce: nonce,
			},
		}
		blockIDs[i] = blocks[i].Block.ID()
	}

	for i := 0; i < 100; i++ {
		cst.cs.db.addBlockMap(&blocks[i])
	}

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		// Just do the lookup/allocation, but don't even store
		cst.cs.db.getBlockMap(blockIDs[i%100])
	}
}
Example #27
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
	}
}
Example #28
0
// announce creates an announcement transaction and submits it to the network.
func (h *Host) announce(addr modules.NetAddress) error {
	// Generate an unlock hash, if necessary.
	if h.UnlockHash == (types.UnlockHash{}) {
		uc, err := h.wallet.NextAddress()
		if err != nil {
			return err
		}
		h.UnlockHash = uc.UnlockHash()
		err = h.save()
		if err != nil {
			return err
		}
	}

	// Create a transaction with a host announcement.
	txnBuilder := h.wallet.StartTransaction()
	announcement := encoding.Marshal(modules.HostAnnouncement{
		IPAddress: addr,
	})
	_ = txnBuilder.AddArbitraryData(append(modules.PrefixHostAnnouncement[:], announcement...))
	txn, parents := txnBuilder.View()
	txnSet := append(parents, txn)

	// Add the transaction to the transaction pool.
	err := h.tpool.AcceptTransactionSet(txnSet)
	if err == modules.ErrDuplicateTransactionSet {
		return errors.New("you have already announced yourself")
	}
	if err != nil {
		return err
	}
	return nil
}
Example #29
0
// TestFindHostAnnouncements probes the findHostAnnouncements function
func TestFindHostAnnouncements(t *testing.T) {
	// Create a block with a host announcement.
	announcement := append(modules.PrefixHostAnnouncement[:], encoding.Marshal(modules.HostAnnouncement{})...)
	b := types.Block{
		Transactions: []types.Transaction{
			types.Transaction{
				ArbitraryData: [][]byte{announcement},
			},
		},
	}
	announcements := findHostAnnouncements(b)
	if len(announcements) != 1 {
		t.Error("host announcement not found in block")
	}

	// Try with an altered prefix
	b.Transactions[0].ArbitraryData[0][0]++
	announcements = findHostAnnouncements(b)
	if len(announcements) != 0 {
		t.Error("host announcement found when there was an invalid prefix")
	}
	b.Transactions[0].ArbitraryData[0][0]--

	// Try with an invalid host encoding.
	b.Transactions[0].ArbitraryData[0][17]++
	announcements = findHostAnnouncements(b)
	if len(announcements) != 0 {
		t.Error("host announcement found when there was an invalid encoding of a host announcement")
	}
}
Example #30
0
// fitsInABlock checks if the transaction is likely to fit in a block.
// Currently there is no limitation on transaction size other than it must fit
// in a block.
func (t Transaction) fitsInABlock() error {
	// Check that the transaction will fit inside of a block, leaving 5kb for
	// overhead.
	if uint64(len(encoding.Marshal(t))) > BlockSizeLimit-5e3 {
		return ErrTransactionTooLarge
	}
	return nil
}