Ejemplo n.º 1
0
func (db *T) PutBlock(b *block.Block, last bool) (e error) {
	writable(&e, db, func(dbtx *bolt.Tx) bool {
		bucket, e := dbtx.CreateBucketIfNotExists([]byte("blocks"))
		if e != nil {
			return false
		}
		encoded, e := b.Encode()
		if e != nil {
			return false
		}
		e = bucket.Put(b.Hash(), encoded)
		if e != nil {
			return false
		}
		// store a reference to this block as a next block
		e = bucket.Put(append(b.PreviousBlockHash, []byte("+")...), b.Hash())
		if e != nil {
			return false
		}

		for i := range b.Transactions {
			// transaction -> block mapping
			e = bucket.Put(append([]byte("T"), b.Transactions[i].Hash()...), b.Hash())
			if e != nil {
				return false
			}
			// link next transactions
			e = bucket.Put(append([]byte(">"), b.Transactions[i].PreviousEnvelopeHash...), b.Transactions[i].Hash())
			if e != nil {
				return false
			}
			// update "unspendable key"
			e = bucket.Delete(append([]byte("<"), b.Transactions[i].PublicKey...))
			if e != nil {
				return false
			}
			// update "spendable key", has to happen after updating the "unspendable" one as it might be the same one
			e = bucket.Put(append([]byte("<"), b.Transactions[i].NextPublicKey...), b.Transactions[i].Hash())
			if e != nil {
				return false
			}
		}

		if last {
			if e = bucket.Put([]byte("last"), b.Hash()); e != nil {
				return false
			}
		}

		return true
	})
	return
}
Ejemplo n.º 2
0
func (db *T) PutBlock(b *block.Block, last bool) error {
	dbtx, err := db.DB.Begin(true)
	success := false
	defer func() {
		if success {
			dbtx.Commit()
		} else {
			dbtx.Rollback()
		}
	}()
	if err != nil {
		return err
	}
	bucket, err := dbtx.CreateBucketIfNotExists([]byte("blocks"))
	if err != nil {
		return err
	}
	encoded, err := b.Encode()
	if err != nil {
		return err
	}
	err = bucket.Put(b.Hash(), encoded)
	if err != nil {
		return err
	}

	for i := range b.Transactions {
		err = bucket.Put(b.Transactions[i].Hash(), b.Hash())
		if err != nil {
			return err
		}
	}

	if last {
		bucket.Put([]byte("last"), b.Hash())
	}
	success = true
	return nil
}
Ejemplo n.º 3
0
func TransactionListener() {
	var msg transaction.T
	var blk *block.Block
	blockChannel := make(chan *block.Block)
	var transactionsPool []transaction.T
	var previousBlockHash types.Hash
	var ch chan transaction.T = make(chan transaction.T)
	router.PermanentSubscribe("/transaction", ch)

	miningEmpty := false

initPool:
	transactionsPool = make([]transaction.T, 0)
loop:
	select {
	case msg = <-ch:
		miningEmpty = false
		env.DB.PutTransaction(msg)
		transactionsPool = append(transactionsPool, msg)
		if blk, _ = env.DB.GetLastBlock(); blk == nil {
			previousBlockHash = types.EmptyHash()
		} else {
			previousBlockHash = blk.Hash()
		}
		if bat := prepareBAT(); bat != nil {
			transactionsPool = append(transactionsPool, bat)
		}
		blk, err := block.NewBlock(previousBlockHash, targetBits(), transactionsPool)
		if err != nil {
			log.Printf("Error while creating a new block: %v", err)
		} else {
			miningFactoryRequests <- MiningFactoryInstantiationRequest{Block: blk, ResponseChannel: blockChannel}
		}
	case blk = <-blockChannel:
		miningEmpty = false
		if lastBlk, _ := env.DB.GetLastBlock(); lastBlk == nil {
			previousBlockHash = types.EmptyHash()
		} else {
			previousBlockHash = blk.Hash()
		}
		isLastBlock := bytes.Compare(blk.PreviousBlockHash, previousBlockHash) == 0
		env.DB.PutBlock(blk, isLastBlock)
		goto initPool
	default:
		if len(transactionsPool) == 0 && !miningEmpty {
			// if there are no transactions to be included into a block, try mining an empty/BAT-only block
			if blk, _ = env.DB.GetLastBlock(); blk == nil {
				previousBlockHash = types.EmptyHash()
			} else {
				previousBlockHash = blk.Hash()
			}
			if bat := prepareBAT(); bat != nil {
				transactionsPool = append(transactionsPool, bat)
			}
			blk, err := block.NewBlock(previousBlockHash, targetBits(), transactionsPool)
			if err != nil {
				log.Printf("Error while creating a new block: %v", err)
			} else {
				miningFactoryRequests <- MiningFactoryInstantiationRequest{Block: blk, ResponseChannel: blockChannel}
				miningEmpty = true
			}

		}
	}
	goto loop
}