Esempio n. 1
0
func TestEncodeDecode(t *testing.T) {
	privateKey := generateKey(t)
	txn1, rand := trans.NewNameReservation("my-new-repository")
	txn1e := trans.NewEnvelope(types.EmptyHash(), txn1)
	txn2, _ := trans.NewNameAllocation("my-new-repository", rand)
	txn2e := trans.NewEnvelope(types.EmptyHash(), txn2)
	txn3, _ := trans.NewNameDeallocation("my-new-repository")
	txn3e := trans.NewEnvelope(types.EmptyHash(), txn3)

	txn1e.Sign(privateKey)
	txn2e.Sign(privateKey)
	txn3e.Sign(privateKey)

	transactions := []*trans.Envelope{txn1e, txn2e, txn3e}
	block, err := NewBlock(types.EmptyHash(), HIGHEST_TARGET, transactions)
	if err != nil {
		t.Errorf("can't create a block because of %v", err)
	}

	enc, err := block.Encode()
	if err != nil {
		t.Errorf("error while encoding block: %v", err)
	}

	block1, err := Decode(enc)
	if err != nil {
		t.Errorf("error while encoding block: %v", err)
	}

	assert.Equal(t, block, block1, "encoded and decoded block should be identical to the original one")
}
Esempio n. 2
0
func TestListRepository(t *testing.T) {

	db, err := NewDB("test.db")
	defer os.Remove("test.db")

	if err != nil {
		t.Errorf("error opening database: %v", err)
	}

	repo := repository.NewRepository("test", repository.PENDING, types.EmptyHash())
	err = db.PutRepository(repo)
	if err != nil {
		t.Errorf("error putting repository: %v", err)
	}

	repo1 := repository.NewRepository("hello_world", repository.ACTIVE, types.EmptyHash())
	err = db.PutRepository(repo1)
	if err != nil {
		t.Errorf("error putting repository: %v", err)
	}

	actualRepositories := db.ListRepositories()
	sort.Strings(actualRepositories)
	expectedRepositories := []string{"test", "hello_world"}
	sort.Strings(expectedRepositories)

	assert.Equal(t, actualRepositories, expectedRepositories)
}
Esempio n. 3
0
func TestNewBlockNoTx(t *testing.T) {
	transactions := []*trans.Envelope{}
	block1, err := NewBlock(types.EmptyHash(), HIGHEST_TARGET, transactions)

	if err != nil {
		t.Errorf("can't create a block because of %v", err)
	}

	assert.Equal(t, transactions, block1.Transactions)
	assert.Equal(t, block1.MerkleRootHash, types.EmptyHash())
}
Esempio n. 4
0
func TestGetNextBlock(t *testing.T) {
	transactions, _ := fixtureSampleTransactions(t)

	blk, err := block.NewBlock(types.EmptyHash(), block.HIGHEST_TARGET, transactions)
	if err != nil {
		t.Errorf("can't create a block because of %v", err)
	}

	blk1, err := block.NewBlock(blk.Hash(), block.HIGHEST_TARGET, []*transaction.Envelope{})
	if err != nil {
		t.Errorf("can't create a block because of %v", err)
	}

	db, err := NewDB("test.db")
	defer os.Remove("test.db")

	if err != nil {
		t.Errorf("error opening database: %v", err)
	}

	err = db.PutBlock(blk, false)
	if err != nil {
		t.Errorf("error putting block: %v", err)
	}

	blk_, err := db.GetNextBlock(types.EmptyHash())
	if err != nil {
		t.Errorf("error getting next block: %v", err)
	}
	assert.Equal(t, blk, blk_)

	err = db.PutBlock(blk1, false)
	if err != nil {
		t.Errorf("error putting block: %v", err)
	}

	blk1_, err := db.GetNextBlock(blk.Hash())
	if err != nil {
		t.Errorf("error getting next block: %v", err)
	}
	assert.Equal(t, blk1_, blk1)

	block0, err := db.GetBlock(types.EmptyHash())
	if err == nil {
		t.Errorf("error getting zero block (no error thrown)")
	}
	if block0 != nil {
		t.Errorf("error getting zero block")
	}
	assert.True(t, nil == block0)
}
Esempio n. 5
0
func TestNewBlockSingleTx(t *testing.T) {
	privateKey := generateKey(t)
	txn1, _ := trans.NewNameReservation("my-new-repository", &privateKey.PublicKey)

	transactions := []trans.T{txn1}
	block1, err := NewBlock(types.EmptyHash(), HIGHEST_TARGET, transactions)

	if err != nil {
		t.Errorf("can't create a block because of %v", err)
		return
	}

	assert.Equal(t, transactions, block1.Transactions)
	assert.NotEqual(t, block1.MerkleRootHash, types.EmptyHash())
}
Esempio n. 6
0
func TestListRefs(t *testing.T) {

	db, err := NewDB("test.db")
	defer os.Remove("test.db")

	if err != nil {
		t.Errorf("error opening database: %v", err)
	}

	repo := repository.NewRepository("myrepo", repository.ACTIVE, types.EmptyHash())
	err = db.PutRepository(repo)
	if err != nil {
		t.Errorf("error putting repository: %v", err)
	}

	ref := util.SHA160([]byte("random"))
	err = db.PutRef("myrepo", "refs/heads/master", ref)
	if err != nil {
		t.Errorf("error putting repository ref: %v", err)
	}
	err = db.PutRef("myrepo", "refs/heads/next", ref)
	if err != nil {
		t.Errorf("error putting repository ref: %v", err)
	}

	refs, err := db.ListRefs("myrepo")
	if err != nil {
		t.Errorf("error listing repository refs: %v", err)
	}

	assert.Equal(t, refs, []string{"refs/heads/master", "refs/heads/next"})
}
Esempio n. 7
0
func NewBlock(previousBlockHash types.Hash, bits uint32, transactions []*trans.Envelope) (*Block, error) {
	encodedTransactions := make([][]byte, len(transactions))
	for i := range transactions {
		t, _ := transactions[i].Encode()
		encodedTransactions[i] = make([]byte, len(t))
		copy(encodedTransactions[i], t)
	}

	var merkleRootHash types.Hash
	var err error

	if len(encodedTransactions) > 0 {
		merkleRootHash, err = merkleRoot(encodedTransactions)
	} else {
		merkleRootHash = types.EmptyHash()
	}

	if err != nil {
		return nil, err
	}
	return &Block{
		Version:           BLOCK_VERSION,
		PreviousBlockHash: previousBlockHash,
		MerkleRootHash:    merkleRootHash,
		Timestamp:         time.Now().UTC().Unix(),
		Bits:              bits,
		Nonce:             0,
		Transactions:      transactions}, nil
}
Esempio n. 8
0
func MiningFactory(srv *context.T) {
	log := srv.Log.New("cmp", "mining")
	var status MiningStatus
	n := 1 // TODO: in the future: srv.Config.Mining.Processes
	minedCh := make(chan *block.Block)
	for i := 0; i < n; i++ {
		ch := make(chan *block.Block)
		status.Miners = append(status.Miners, Miner{signallingChannel: ch})
		go block.Miner(ch, minedCh)
	}
	ch := srv.Router.Sub("/transaction")
	transactionsPool := make([]*transaction.Envelope, 0)
	var previousBlockHash types.Hash

	// Setup previous block hash
	if blk, _ := srv.DB.GetLastBlock(); blk == nil {
		previousBlockHash = types.EmptyHash()
	} else {
		previousBlockHash = blk.Hash()
	}

loop:
	select {
	case txni := <-ch:
		if txn, ok := txni.(*transaction.Envelope); ok {
			transactionsPool = append(transactionsPool, txn)
			stopMiners(status)
			mineBlock(status, srv, log, previousBlockHash, transactionsPool)
		}
	case blk := <-minedCh:
		if bytes.Compare(blk.PreviousBlockHash, previousBlockHash) == 0 {
			log.Debug("mined", "block", blk)
			for i := range blk.Transactions {
				for j := range transactionsPool {
					if bytes.Compare(transactionsPool[j].Hash(), blk.Transactions[i].Hash()) == 0 {
						transactionsPool = append(transactionsPool[0:j], transactionsPool[j+1:]...)
					}
				}
			}
			previousBlockHash = blk.Hash()
			stopMiners(status)
			err := srv.DB.PutBlock(blk, true)
			if err != nil {
				log.Error("error while serializing block", "block", blk.Hash(), "err", err)
			} else {
				srv.Router.Pub(blk, "/block", "/block/last")
				mineBlock(status, srv, log, previousBlockHash, transactionsPool)
			}
		}
	case reqi := <-miningFactoryRequests:
		if req, ok := reqi.(*MiningFactoryStatusRequest); ok {
			req.ResponseChannel <- status
		}
	case <-time.After(time.Second * 1):
		if key, _ := srv.DB.GetMainKey(); key != nil && len(transactionsPool) == 0 && status.AvailableMiners() == n {
			mineBlock(status, srv, log, previousBlockHash, make([]*transaction.Envelope, 0))
		}
	}
	goto loop
}
Esempio n. 9
0
func TestGetTransactionBlock(t *testing.T) {
	transactions := fixtureSampleTransactions(t)

	block, err := block.NewBlock(types.EmptyHash(), block.HIGHEST_TARGET, transactions)
	if err != nil {
		t.Errorf("can't create a block because of %v", err)
	}

	db, err := NewDB("test.db")
	defer os.Remove("test.db")

	if err != nil {
		t.Errorf("error opening database: %v", err)
	}
	err = db.PutBlock(block, false)
	if err != nil {
		t.Errorf("error putting block: %v", err)
	}

	// Block<->transaction indexing
	for i := range transactions {
		block1, err := db.GetTransactionBlock(transactions[i].Hash())
		if err != nil {
			t.Errorf("error getting transaction's block: %v", err)
		}
		assert.Equal(t, block, block1)
	}
}
Esempio n. 10
0
func merkleRoot(data [][]byte) (types.Hash, error) {
	tree := merkle.NewTree()
	err := tree.Generate(data, fastsha256.New())
	if err != nil {
		return types.EmptyHash(), err
	}
	return tree.Root().Hash, err
}
Esempio n. 11
0
func merkleRoot(data [][]byte) (types.Hash, error) {
	if len(data) == 1 { // FIXME: a workaround for trees with one element
		data = append(data, []byte{})
	}
	tree := merkle.NewTree()
	err := tree.Generate(data, fastsha256.New())
	if err != nil {
		return types.EmptyHash(), err
	}
	return types.NewHash(tree.Root().Hash), err
}
Esempio n. 12
0
func TestPutGetBlock(t *testing.T) {
	privateKey := generateECDSAKey(t)
	txn1, rand := transaction.NewNameReservation("my-new-repository", &privateKey.PublicKey)
	txn2, _ := transaction.NewNameAllocation("my-new-repository", rand, privateKey)
	txn3, _ := transaction.NewNameDeallocation("my-new-repository", privateKey)

	transactions := []transaction.T{txn1, txn2, txn3}
	block, err := block.NewBlock(types.EmptyHash(), block.HIGHEST_TARGET, transactions)
	if err != nil {
		t.Errorf("can't create a block because of %v", err)
	}

	db, err := NewDB("test.db")
	defer os.Remove("test.db")

	if err != nil {
		t.Errorf("error opening database: %v", err)
	}
	err = db.PutBlock(block, false)
	if err != nil {
		t.Errorf("error putting block: %v", err)
	}
	block1, err := db.GetBlock(block.Hash())
	if err != nil {
		t.Errorf("error getting block: %v", err)
	}
	if block1 == nil {
		t.Errorf("error getting block %v", block.Hash())
	}
	assert.Equal(t, block, block1)

	// Attempt fetching the last one
	block1, err = db.GetLastBlock()
	if err != nil {
		t.Errorf("error getting block: %v", err)
	}
	if block1 != nil {
		t.Errorf("error getting block, there should be no last block")
	}

	// Set the last one
	err = db.PutBlock(block, true)
	if err != nil {
		t.Errorf("error putting block: %v", err)
	}
	block1, err = db.GetLastBlock()
	if err != nil {
		t.Errorf("error getting last block: %v", err)
	}
	if block1 == nil {
		t.Errorf("error getting block, there should be a last block")
	}
	assert.Equal(t, block, block1)
}
Esempio n. 13
0
func (db *T) GetNextTransactionHash(hash []byte) (h types.Hash, e error) {
	readable(&e, db, func(dbtx *bolt.Tx) {
		bucket := dbtx.Bucket([]byte("blocks"))
		if bucket != nil {
			h = bucket.Get(append([]byte(">"), hash...))
			if h == nil {
				h = types.EmptyHash()
			}
		}
	})
	return
}
Esempio n. 14
0
func TestGetNextTransactionHash(t *testing.T) {
	transactions, _ := fixtureSampleTransactions(t)

	block, err := block.NewBlock(types.EmptyHash(), block.HIGHEST_TARGET, transactions)
	if err != nil {
		t.Errorf("can't create a block because of %v", err)
	}

	db, err := NewDB("test.db")
	defer os.Remove("test.db")

	if err != nil {
		t.Errorf("error opening database: %v", err)
	}
	err = db.PutBlock(block, false)
	if err != nil {
		t.Errorf("error putting block: %v", err)
	}

	tx, err := db.GetNextTransactionHash(transactions[0].Hash())
	if err != nil {
		t.Errorf("error getting next transaction: %v", err)
	}
	assert.True(t, bytes.Compare(tx, transactions[1].Hash()) == 0)

	tx, err = db.GetNextTransactionHash(transactions[1].Hash())
	if err != nil {
		t.Errorf("error getting next transaction: %v", err)
	}
	assert.True(t, bytes.Compare(tx, transactions[2].Hash()) == 0)

	tx, err = db.GetNextTransactionHash(transactions[2].Hash())
	if err != nil {
		t.Errorf("error getting next transaction: %v", err)
	}
	assert.True(t, bytes.Compare(tx, types.EmptyHash()) == 0)

}
Esempio n. 15
0
func TestNewBlock(t *testing.T) {
	privateKey := generateKey(t)
	txn1, rand := trans.NewNameReservation("my-new-repository")
	txn1e := trans.NewEnvelope(types.EmptyHash(), txn1)
	txn2, _ := trans.NewNameAllocation("my-new-repository", rand)
	txn2e := trans.NewEnvelope(types.EmptyHash(), txn2)
	txn3, _ := trans.NewNameDeallocation("my-new-repository")
	txn3e := trans.NewEnvelope(types.EmptyHash(), txn3)

	txn1e.Sign(privateKey)
	txn2e.Sign(privateKey)
	txn3e.Sign(privateKey)

	transactions := []*trans.Envelope{txn1e, txn2e, txn3e}
	block1, err := NewBlock(types.EmptyHash(), HIGHEST_TARGET, transactions)

	if err != nil {
		t.Errorf("can't create a block because of %v", err)
	}

	assert.Equal(t, transactions, block1.Transactions)
	assert.NotEqual(t, block1.MerkleRootHash, types.EmptyHash())
}
Esempio n. 16
0
func fixtureSampleTransactions(t *testing.T) ([]*transaction.Envelope, *ecdsa.PrivateKey) {
	privateKey := generateECDSAKey(t)
	txn1, rand := transaction.NewNameReservation("my-new-repository")
	txn1e := transaction.NewEnvelope(types.EmptyHash(), txn1)
	txn1e.Sign(privateKey)
	txn2, _ := transaction.NewNameAllocation("my-new-repository", rand)
	txn2e := transaction.NewEnvelope(txn1e.Hash(), txn2)
	txn2e.Sign(privateKey)
	txn3, _ := transaction.NewNameDeallocation("my-new-repository")
	txn3e := transaction.NewEnvelope(txn2e.Hash(), txn3)
	txn3e.Sign(privateKey)

	return []*transaction.Envelope{txn1e, txn2e, txn3e}, privateKey
}
Esempio n. 17
0
func TestPutGetBlock(t *testing.T) {
	transactions, _ := fixtureSampleTransactions(t)

	blk, err := block.NewBlock(types.EmptyHash(), block.HIGHEST_TARGET, transactions)
	if err != nil {
		t.Errorf("can't create a block because of %v", err)
	}

	db, err := NewDB("test.db")
	defer os.Remove("test.db")

	if err != nil {
		t.Errorf("error opening database: %v", err)
	}
	err = db.PutBlock(blk, false)
	if err != nil {
		t.Errorf("error putting block: %v", err)
	}
	block1, err := db.GetBlock(blk.Hash())
	if err != nil {
		t.Errorf("error getting block: %v", err)
	}
	if block1 == nil {
		t.Errorf("error getting block %v", blk.Hash())
	}
	assert.Equal(t, blk, block1)

	// Attempt fetching the last one
	block1, err = db.GetLastBlock()
	if err != nil {
		t.Errorf("error getting block: %v", err)
	}
	if block1 != nil {
		t.Errorf("error getting block, there should be no last block")
	}

	// Set the last one
	err = db.PutBlock(blk, true)
	if err != nil {
		t.Errorf("error putting block: %v", err)
	}
	block1, err = db.GetLastBlock()
	if err != nil {
		t.Errorf("error getting last block: %v", err)
	}
	if block1 == nil {
		t.Errorf("error getting block, there should be a last block")
	}
	assert.Equal(t, blk, block1)
}
Esempio n. 18
0
func TestEncodeDecodeEmptyBlock(t *testing.T) {
	transactions := []*trans.Envelope{}
	block, err := NewBlock(types.EmptyHash(), HIGHEST_TARGET, transactions)
	if err != nil {
		t.Errorf("can't create a block because of %v", err)
	}

	enc, err := block.Encode()
	if err != nil {
		t.Errorf("error while encoding block: %v", err)
	}

	block1, err := Decode(enc)
	if err != nil {
		t.Errorf("error while encoding block: %v", err)
	}

	assert.Equal(t, block, block1, "encoded and decoded block should be identical to the original one")
}
Esempio n. 19
0
func TestTransactionConfirmations(t *testing.T) {
	db, err := NewDB("test.db")
	defer os.Remove("test.db")

	if err != nil {
		t.Errorf("error opening database: %v", err)
	}

	transactions := fixtureSampleTransactions(t)
	confirmationsTest := func(count int, note string) {
		for i := range transactions {
			confirmations, err := db.GetTransactionConfirmations(transactions[i].Hash())
			if err != nil {
				t.Errorf("error getting transaction's confirmations: %v", err)
			}
			assert.Equal(t, confirmations, count, note)
		}
	}

	blk, err := block.NewBlock(types.EmptyHash(), block.HIGHEST_TARGET, transactions)

	if err != nil {
		t.Errorf("can't create a block because of %v", err)
	}

	confirmationsTest(0, "no transaction was confirmed yet")

	err = db.PutBlock(blk, true)
	if err != nil {
		t.Errorf("error putting block: %v", err)
	}

	confirmationsTest(1, "there should be one confirmation")

	anotherSampleOfTransactions := fixtureSampleTransactions(t)

	blk, err = block.NewBlock(blk.Hash(), block.HIGHEST_TARGET, anotherSampleOfTransactions)
	err = db.PutBlock(blk, true)
	if err != nil {
		t.Errorf("error putting block: %v", err)
	}

}
Esempio n. 20
0
func TestEnvelopeSignVerify(t *testing.T) {
	privateKey := generateKey(t)
	txn, _ := NewNameReservation("my-new-repository")

	e := NewEnvelope(types.EmptyHash(), txn)

	err := e.Sign(privateKey)
	if err != nil {
		t.Errorf("Can't sign the envelope: %v", err)
	}

	v, err := e.Verify()

	if err != nil {
		t.Errorf("Can't verify the envelope: %v", err)
	}

	assert.True(t, v)

}
Esempio n. 21
0
func TestPutGetDeleteTransaction(t *testing.T) {
	privateKey := generateECDSAKey(t)
	txn1, _ := transaction.NewNameReservation("my-new-repository")
	txn1e := transaction.NewEnvelope(types.EmptyHash(), txn1)
	txn1e.Sign(privateKey)

	db, err := NewDB("test.db")
	defer os.Remove("test.db")

	if err != nil {
		t.Errorf("error opening database: %v", err)
	}

	err = db.PutTransaction(txn1e)
	if err != nil {
		t.Errorf("error putting transaction: %v", err)
	}

	tx, err := db.GetTransaction(txn1e.Hash())
	if err != nil {
		t.Errorf("error getting transaction: %v", err)
	}

	assert.Equal(t, tx, txn1e)

	err = db.DeleteTransaction(txn1e.Hash())
	if err != nil {
		t.Errorf("error getting transaction: %v", err)
	}

	tx, err = db.GetTransaction(txn1e.Hash())
	if err != nil {
		t.Errorf("error getting transaction: %v", err)
	}

	assert.Nil(t, tx)

}
Esempio n. 22
0
func TestGetPreviousEnvelopeHashForPublicKey(t *testing.T) {
	transactions, _ := fixtureSampleTransactions(t)

	block, err := block.NewBlock(types.EmptyHash(), block.HIGHEST_TARGET, transactions)
	if err != nil {
		t.Errorf("can't create a block because of %v", err)
	}

	db, err := NewDB("test.db")
	defer os.Remove("test.db")

	if err != nil {
		t.Errorf("error opening database: %v", err)
	}
	err = db.PutBlock(block, false)
	if err != nil {
		t.Errorf("error putting block: %v", err)
	}

	dec, err := keys.DecodeECDSAPublicKey(transactions[2].NextPublicKey)
	if err != nil {
		t.Errorf("error decoding ECDSA pubkey: %v", err)
	}
	tx, err := db.GetPreviousEnvelopeHashForPublicKey(dec)
	if err != nil {
		t.Errorf("error getting previous transaction's for a pubkey: %v", err)
	}
	assert.True(t, bytes.Compare(tx, transactions[2].Hash()) == 0)

	privateKey := generateECDSAKey(t)

	tx, err = db.GetPreviousEnvelopeHashForPublicKey(&privateKey.PublicKey)
	if err != nil {
		t.Errorf("error getting previous transaction's for a pubkey: %v", err)
	}
	assert.Nil(t, tx)

}
Esempio n. 23
0
func TestEnvelopeEncodeDecode(t *testing.T) {
	privateKey := generateKey(t)
	txn, _ := NewNameReservation("my-new-repository")

	e := NewEnvelope(types.EmptyHash(), txn)

	err := e.Sign(privateKey)
	if err != nil {
		t.Errorf("Can't sign the envelope: %v", err)
	}

	enc, err := e.Encode()
	if err != nil {
		t.Errorf("Can't encode the envelope: %v", err)
	}

	e1, err := DecodeEnvelope(enc)
	if err != nil {
		t.Errorf("Can't decode the envelope: %v", err)
	}

	assert.Equal(t, e, e1)
}
Esempio n. 24
0
func TestPutGetRepository(t *testing.T) {

	db, err := NewDB("test.db")
	defer os.Remove("test.db")

	if err != nil {
		t.Errorf("error opening database: %v", err)
	}

	repo := repository.NewRepository("test", repository.PENDING, types.EmptyHash())
	err = db.PutRepository(repo)
	if err != nil {
		t.Errorf("error putting repository: %v", err)
	}
	repo1, err := db.GetRepository("test")
	if err != nil {
		t.Errorf("error getting repository: %v", err)
	}
	if repo1 == nil {
		t.Errorf("error getting repository `test'")
	}
	assert.Equal(t, repo, repo1)
}
Esempio n. 25
0
func TestPutGetRef(t *testing.T) {

	db, err := NewDB("test.db")
	defer os.Remove("test.db")

	if err != nil {
		t.Errorf("error opening database: %v", err)
	}

	repo := repository.NewRepository("myrepo", repository.ACTIVE, types.EmptyHash())
	err = db.PutRepository(repo)
	if err != nil {
		t.Errorf("error putting repository: %v", err)
	}

	// before the ref is set...
	ref0, err := db.GetRef("myrepo", "refs/heads/master")
	if err != nil {
		t.Errorf("error getting repository ref: %v", err)
	}
	assert.True(t, ref0.Equals(repository.EmptyRef()))

	ref := util.SHA160([]byte("random"))
	err = db.PutRef("myrepo", "refs/heads/master", ref)
	if err != nil {
		t.Errorf("error putting repository ref: %v", err)
	}
	ref1, err := db.GetRef("myrepo", "refs/heads/master")
	if err != nil {
		t.Errorf("error getting repository ref: %v", err)
	}
	if ref1 == nil {
		t.Errorf("error getting repository ref `refs/heads/master'")
	}
	assert.True(t, bytes.Compare(ref, ref1) == 0)
}
Esempio n. 26
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
}