Beispiel #1
0
func buildTestBlock() *protos.Block {
	transactions := []*protos.Transaction{}
	tx, _ := buildTestTx()
	transactions = append(transactions, tx)
	block := protos.NewBlock(transactions)
	return block
}
Beispiel #2
0
// CommitTxBatch - gets invoked when the current transaction-batch needs to be committed
// This function returns successfully iff the transactions details and state changes (that
// may have happened during execution of this transaction-batch) have been committed to permanent storage
func (ledger *Ledger) CommitTxBatch(id interface{}, transactions []*protos.Transaction, proof []byte) error {
	err := ledger.checkValidIDCommitORRollback(id)
	if err != nil {
		return err
	}

	success := true
	defer ledger.resetForNextTxGroup(success)
	defer ledger.blockchain.blockPersistenceStatus(success)

	stateHash, err := ledger.state.GetHash()
	if err != nil {
		success = false
		return err
	}

	writeBatch := gorocksdb.NewWriteBatch()
	block := protos.NewBlock(transactions)
	newBlockNumber, err := ledger.blockchain.addPersistenceChangesForNewBlock(context.TODO(), block, stateHash, writeBatch)
	if err != nil {
		success = false
		return err
	}
	ledger.state.AddChangesForPersistence(newBlockNumber, writeBatch)
	opt := gorocksdb.NewDefaultWriteOptions()
	dbErr := db.GetDBHandle().DB.Write(opt, writeBatch)
	if dbErr != nil {
		success = false
		return dbErr
	}
	producer.Send(producer.CreateBlockEvent(block))
	return nil
}
Beispiel #3
0
func buildTestBlock(t *testing.T) (*protos.Block, error) {
	transactions := []*protos.Transaction{}
	tx, _ := buildTestTx(t)
	transactions = append(transactions, tx)
	block := protos.NewBlock(transactions, nil)
	return block, nil
}
func TestIndexes_GetTransactionByUUID(t *testing.T) {
	testDBWrapper.CreateFreshDB(t)
	testBlockchainWrapper := newTestBlockchainWrapper(t)
	tx1, uuid1 := buildTestTx(t)
	tx2, uuid2 := buildTestTx(t)
	block1 := protos.NewBlock([]*protos.Transaction{tx1, tx2}, nil)
	testBlockchainWrapper.addNewBlock(block1, []byte("stateHash1"))

	tx3, uuid3 := buildTestTx(t)
	tx4, uuid4 := buildTestTx(t)
	block2 := protos.NewBlock([]*protos.Transaction{tx3, tx4}, nil)
	testBlockchainWrapper.addNewBlock(block2, []byte("stateHash2"))

	testutil.AssertEquals(t, testBlockchainWrapper.getTransactionByUUID(uuid1), tx1)
	testutil.AssertEquals(t, testBlockchainWrapper.getTransactionByUUID(uuid2), tx2)
	testutil.AssertEquals(t, testBlockchainWrapper.getTransactionByUUID(uuid3), tx3)
	testutil.AssertEquals(t, testBlockchainWrapper.getTransactionByUUID(uuid4), tx4)
}
Beispiel #5
0
func (testWrapper *blockchainTestWrapper) populateBlockChainWithSampleData() (blocks []*protos.Block, hashes [][]byte, err error) {
	var allBlocks []*protos.Block
	var allHashes [][]byte

	// -----------------------------<Genesis block>-------------------------------
	// Add the first (genesis block)
	block1 := protos.NewBlock(nil, nil)
	allBlocks = append(allBlocks, block1)
	allHashes = append(allHashes, []byte("stateHash1"))
	testWrapper.addNewBlock(block1, []byte("stateHash1"))

	// -----------------------------</Genesis block>------------------------------

	// -----------------------------<Block 2>-------------------------------------
	// Deploy a chaincode
	transaction2a, err := protos.NewTransaction(protos.ChaincodeID{Path: "Contracts"}, testutil.GenerateUUID(testWrapper.t), "NewContract", []string{"name: MyContract1, code: var x; function setX(json) {x = json.x}}"})
	if err != nil {
		return nil, nil, err
	}
	// Now we add the transaction to the block 2 and add the block to the chain
	transactions2a := []*protos.Transaction{transaction2a}
	block2 := protos.NewBlock(transactions2a, nil)

	allBlocks = append(allBlocks, block2)
	allHashes = append(allHashes, []byte("stateHash2"))
	testWrapper.addNewBlock(block2, []byte("stateHash2"))
	// -----------------------------</Block 2>------------------------------------

	// -----------------------------<Block 3>-------------------------------------
	// Create a transaction'
	transaction3a, err := protos.NewTransaction(protos.ChaincodeID{Path: "MyContract"}, testutil.GenerateUUID(testWrapper.t), "setX", []string{"{x: \"hello\"}"})
	if err != nil {
		return nil, nil, err
	}
	// Create the third block and add it to the chain
	transactions3a := []*protos.Transaction{transaction3a}
	block3 := protos.NewBlock(transactions3a, nil)
	allBlocks = append(allBlocks, block3)
	allHashes = append(allHashes, []byte("stateHash3"))
	testWrapper.addNewBlock(block3, []byte("stateHash3"))

	// -----------------------------</Block 3>------------------------------------
	return allBlocks, allHashes, nil
}
Beispiel #6
0
// GetTXBatchPreviewBlock returns a preview block that will have the same
// block.GetHash() result as the block commited to the database if
// ledger.CommitTxBatch is called with the same parameters. If the state is modified
// by a transaction between these two calls, the hash will be different. The
// preview block does not include non-hashed data such as the local timestamp.
func (ledger *Ledger) GetTXBatchPreviewBlock(id interface{},
	transactions []*protos.Transaction, proof []byte) (*protos.Block, error) {
	err := ledger.checkValidIDCommitORRollback(id)
	if err != nil {
		return nil, err
	}
	stateHash, err := ledger.state.GetHash()
	if err != nil {
		return nil, err
	}
	return ledger.blockchain.buildBlock(protos.NewBlock(transactions), stateHash), nil
}
func TestBlockchainBlockLedgerCommitTimestamp(t *testing.T) {
	testDBWrapper.CreateFreshDB(t)
	blockchainTestWrapper := newTestBlockchainWrapper(t)
	block1 := protos.NewBlock(nil)
	startTime := util.CreateUtcTimestamp()
	time.Sleep(2 * time.Second)
	blockchainTestWrapper.addNewBlock(block1, []byte("stateHash1"))
	lastBlock := blockchainTestWrapper.getLastBlock()
	if lastBlock.NonHashData == nil {
		t.Fatal("Expected block to have non-hash-data, but it was nil")
	}
	if lastBlock.NonHashData.LocalLedgerCommitTimestamp == nil {
		t.Fatal("Expected block to have non-hash-data timestamp, but it was nil")
	}
	if startTime.Seconds >= lastBlock.NonHashData.LocalLedgerCommitTimestamp.Seconds {
		t.Fatal("Expected block time to be after start time")
	}
}
Beispiel #8
0
// CommitTxBatch - gets invoked when the current transaction-batch needs to be committed
// This function returns successfully iff the transactions details and state changes (that
// may have happened during execution of this transaction-batch) have been committed to permanent storage
func (ledger *Ledger) CommitTxBatch(id interface{}, transactions []*protos.Transaction, transactionResults []*protos.TransactionResult, metadata []byte) error {
	err := ledger.checkValidIDCommitORRollback(id)
	if err != nil {
		return err
	}

	stateHash, err := ledger.state.GetHash()
	if err != nil {
		ledger.resetForNextTxGroup(false)
		ledger.blockchain.blockPersistenceStatus(false)
		return err
	}

	writeBatch := gorocksdb.NewWriteBatch()
	defer writeBatch.Destroy()
	block := protos.NewBlock(transactions, metadata)
	block.NonHashData = &protos.NonHashData{TransactionResults: transactionResults}
	newBlockNumber, err := ledger.blockchain.addPersistenceChangesForNewBlock(context.TODO(), block, stateHash, writeBatch)
	if err != nil {
		ledger.resetForNextTxGroup(false)
		ledger.blockchain.blockPersistenceStatus(false)
		return err
	}
	ledger.state.AddChangesForPersistence(newBlockNumber, writeBatch)
	opt := gorocksdb.NewDefaultWriteOptions()
	defer opt.Destroy()
	dbErr := db.GetDBHandle().DB.Write(opt, writeBatch)
	if dbErr != nil {
		ledger.resetForNextTxGroup(false)
		ledger.blockchain.blockPersistenceStatus(false)
		return dbErr
	}

	ledger.resetForNextTxGroup(true)
	ledger.blockchain.blockPersistenceStatus(true)

	sendProducerBlockEvent(block)
	return nil
}
func TestBlockChain_SingleBlock(t *testing.T) {
	testDBWrapper.CreateFreshDB(t)
	blockchainTestWrapper := newTestBlockchainWrapper(t)
	blockchain := blockchainTestWrapper.blockchain

	// Create the Chaincode specification
	chaincodeSpec := &protos.ChaincodeSpec{Type: protos.ChaincodeSpec_GOLANG,
		ChaincodeID: &protos.ChaincodeID{Path: "Contracts"},
		CtorMsg:     &protos.ChaincodeInput{Function: "Initialize", Args: []string{"param1"}}}
	chaincodeDeploymentSepc := &protos.ChaincodeDeploymentSpec{ChaincodeSpec: chaincodeSpec}
	uuid := testutil.GenerateUUID(t)
	newChaincodeTx, err := protos.NewChaincodeDeployTransaction(chaincodeDeploymentSepc, uuid)
	testutil.AssertNoError(t, err, "Failed to create new chaincode Deployment Transaction")
	t.Logf("New chaincode tx: %v", newChaincodeTx)

	block1 := protos.NewBlock([]*protos.Transaction{newChaincodeTx})
	blockNumber := blockchainTestWrapper.addNewBlock(block1, []byte("stateHash1"))
	t.Logf("New chain: %v", blockchain)
	testutil.AssertEquals(t, blockNumber, uint64(0))
	testutil.AssertEquals(t, blockchain.getSize(), uint64(1))
	testutil.AssertEquals(t, blockchainTestWrapper.fetchBlockchainSizeFromDB(), uint64(1))
}
Beispiel #10
0
func TestVerifyChain(t *testing.T) {
	ledgerTestWrapper := createFreshDBAndTestLedgerWrapper(t)
	ledger := ledgerTestWrapper.ledger

	// Build a big blockchain
	for i := 0; i < 100; i++ {
		ledger.BeginTxBatch(i)
		ledger.TxBegin("txUuid" + strconv.Itoa(i))
		ledger.SetState("chaincode"+strconv.Itoa(i), "key"+strconv.Itoa(i), []byte("value"+strconv.Itoa(i)))
		ledger.TxFinished("txUuid"+strconv.Itoa(i), true)
		transaction, _ := buildTestTx(t)
		ledger.CommitTxBatch(i, []*protos.Transaction{transaction}, nil, []byte("proof"))
	}

	// Verify the chain
	for lowBlock := uint64(0); lowBlock < ledger.GetBlockchainSize()-1; lowBlock++ {
		testutil.AssertEquals(t, ledgerTestWrapper.VerifyChain(ledger.GetBlockchainSize()-1, lowBlock), uint64(0))
	}
	for highBlock := ledger.GetBlockchainSize() - 1; highBlock > 0; highBlock-- {
		testutil.AssertEquals(t, ledgerTestWrapper.VerifyChain(highBlock, 0), uint64(0))
	}

	// Add bad blocks and test
	badBlock := protos.NewBlock(nil, nil)
	badBlock.PreviousBlockHash = []byte("evil")
	for i := uint64(0); i < ledger.GetBlockchainSize(); i++ {
		goodBlock := ledgerTestWrapper.GetBlockByNumber(i)
		ledger.PutRawBlock(badBlock, i)
		for lowBlock := uint64(0); lowBlock < ledger.GetBlockchainSize()-1; lowBlock++ {
			if i >= lowBlock {
				expected := uint64(i + 1)
				if i == ledger.GetBlockchainSize()-1 {
					expected--
				}
				testutil.AssertEquals(t, ledgerTestWrapper.VerifyChain(ledger.GetBlockchainSize()-1, lowBlock), expected)
			} else {
				testutil.AssertEquals(t, ledgerTestWrapper.VerifyChain(ledger.GetBlockchainSize()-1, lowBlock), uint64(0))
			}
		}
		for highBlock := ledger.GetBlockchainSize() - 1; highBlock > 0; highBlock-- {
			if i <= highBlock {
				expected := uint64(i + 1)
				if i == highBlock {
					expected--
				}
				testutil.AssertEquals(t, ledgerTestWrapper.VerifyChain(highBlock, 0), expected)
			} else {
				testutil.AssertEquals(t, ledgerTestWrapper.VerifyChain(highBlock, 0), uint64(0))
			}
		}
		ledgerTestWrapper.PutRawBlock(goodBlock, i)
	}

	// Test edge cases
	_, err := ledger.VerifyChain(2, 10)
	testutil.AssertError(t, err, "Expected error as high block is less than low block")
	_, err = ledger.VerifyChain(2, 2)
	testutil.AssertError(t, err, "Expected error as high block is equal to low block")
	_, err = ledger.VerifyChain(0, 100)
	testutil.AssertError(t, err, "Expected error as high block is out of bounds")
}