Пример #1
0
func TestBlockNonHashData(t *testing.T) {
	block1 := NewBlock(nil)
	block2 := NewBlock(nil)
	time1 := util.CreateUtcTimestamp()
	time.Sleep(100 * time.Millisecond)
	time2 := util.CreateUtcTimestamp()
	block1.NonHashData = &NonHashData{LocalLedgerCommitTimestamp: time1}
	block2.NonHashData = &NonHashData{LocalLedgerCommitTimestamp: time2}
	hash1, err := block1.GetHash()
	if err != nil {
		t.Fatalf("Error generating block1 hash: %s", err)
	}
	hash2, err := block2.GetHash()
	if err != nil {
		t.Fatalf("Error generating block2 hash: %s", err)
	}
	if bytes.Compare(hash1, hash2) != 0 {
		t.Fatalf("Expected block hashes to be equal, but there were not")
	}
	if time1 != block1.NonHashData.LocalLedgerCommitTimestamp {
		t.Fatalf("Expected time1 and block1 times to be equal, but there were not")
	}
	if time2 != block2.NonHashData.LocalLedgerCommitTimestamp {
		t.Fatalf("Expected time2 and block2 times to be equal, but there were not")
	}
}
Пример #2
0
func (blockchain *blockchain) addPersistenceChangesForNewBlock(ctx context.Context,
	block *protos.Block, stateHash []byte, writeBatch *gorocksdb.WriteBatch) (uint64, error) {
	block = blockchain.buildBlock(block, stateHash)
	if block.NonHashData == nil {
		block.NonHashData = &protos.NonHashData{LocalLedgerCommitTimestamp: util.CreateUtcTimestamp()}
	} else {
		block.NonHashData.LocalLedgerCommitTimestamp = util.CreateUtcTimestamp()
	}
	blockNumber := blockchain.size
	blockHash, err := block.GetHash()
	if err != nil {
		return 0, err
	}
	blockBytes, blockBytesErr := block.Bytes()
	if blockBytesErr != nil {
		return 0, blockBytesErr
	}
	writeBatch.PutCF(db.GetDBHandle().BlockchainCF, encodeBlockNumberDBKey(blockNumber), blockBytes)
	writeBatch.PutCF(db.GetDBHandle().BlockchainCF, blockCountKey, encodeUint64(blockNumber+1))
	if blockchain.indexer.isSynchronous() {
		blockchain.indexer.createIndexesSync(block, blockNumber, blockHash, writeBatch)
	}
	blockchain.lastProcessedBlock = &lastProcessedBlock{block, blockNumber, blockHash}
	return blockNumber, nil
}
Пример #3
0
// SendTransactionsToPeer current temporary mechanism of forwarding transactions to the configured Validator.
func sendTransactionsToThisPeer(peerAddress string, transaction *pb.Transaction) *pb.Response {
	conn, err := NewPeerClientConnectionWithAddress(peerAddress)
	if err != nil {
		return &pb.Response{Status: pb.Response_FAILURE, Msg: []byte(fmt.Sprintf("Error sending transactions to peer address=%s:  %s", peerAddress, err))}
	}
	serverClient := pb.NewPeerClient(conn)
	stream, err := serverClient.Chat(context.Background())
	if err != nil {
		return &pb.Response{Status: pb.Response_FAILURE, Msg: []byte(fmt.Sprintf("Error sending transactions to peer address=%s:  %s", peerAddress, err))}
	}
	defer stream.CloseSend()
	peerLogger.Debug("Sending transaction %s to self", transaction.Type)
	data, err := proto.Marshal(transaction)
	if err != nil {
		return &pb.Response{Status: pb.Response_FAILURE, Msg: []byte(fmt.Sprintf("Error sending transaction to local peer: %s", err))}
	}
	var ttyp pb.OpenchainMessage_Type
	if transaction.Type == pb.Transaction_CHAINCODE_EXECUTE || transaction.Type == pb.Transaction_CHAINCODE_NEW {
		ttyp = pb.OpenchainMessage_CHAIN_TRANSACTION
	} else {
		ttyp = pb.OpenchainMessage_CHAIN_QUERY
	}

	msg := &pb.OpenchainMessage{Type: ttyp, Payload: data, Timestamp: util.CreateUtcTimestamp()}
	peerLogger.Debug("Sending message %s with timestamp %v to self", msg.Type, msg.Timestamp)
	stream.Send(msg)

	waitc := make(chan struct{})
	var response *pb.Response
	go func() {
		// Make sure to close the wait channel
		defer close(waitc)
		for {
			in, err := stream.Recv()
			if err == io.EOF {
				// read done.
				response = &pb.Response{Status: pb.Response_FAILURE, Msg: []byte(fmt.Sprintf("Error sending transactions to this peer, received EOF when expecting %s", pb.OpenchainMessage_DISC_HELLO))}
				return
			}
			if err != nil {
				response = &pb.Response{Status: pb.Response_FAILURE, Msg: []byte(fmt.Sprintf("Unexpected error receiving on stream from peer (%s):  %s", peerAddress, err))}
				return
			}
			if in.Type == pb.OpenchainMessage_RESPONSE {
				peerLogger.Debug("Received %s message as expected, exiting out of receive loop", in.Type)
				response = &pb.Response{}
				err = proto.Unmarshal(in.Payload, response)
				if err != nil {
					response = &pb.Response{Status: pb.Response_FAILURE, Msg: []byte(fmt.Sprintf("Error unpacking Payload from %s message: %s", pb.OpenchainMessage_CONSENSUS, err))}
				}
				return
			}
			peerLogger.Debug("Got unexpected message %s, with bytes length = %d,  doing nothing", in.Type, len(in.Payload))
			response = &pb.Response{Status: pb.Response_FAILURE, Msg: []byte(fmt.Sprintf("Got unexpected message %s, with bytes length = %d,  doing nothing", in.Type, len(in.Payload)))}
			return
		}
	}()
	<-waitc
	return response
}
Пример #4
0
func (i *Noops) processTransactions() error {
	timestamp := util.CreateUtcTimestamp()
	if logger.IsEnabledFor(logging.DEBUG) {
		logger.Debug("Starting TX batch with timestamp: %v", timestamp)
	}
	if err := i.stack.BeginTxBatch(timestamp); err != nil {
		return err
	}

	// Grab all transactions from the FIFO queue and run them in order
	txarr := i.txQ.getTXs()
	if logger.IsEnabledFor(logging.DEBUG) {
		logger.Debug("Executing batch of %d transactions with timestamp %v", len(txarr), timestamp)
	}
	_, err := i.stack.ExecTxs(timestamp, txarr)

	//consensus does not need to understand transaction errors, errors here are
	//actual ledger errors, and often irrecoverable
	if err != nil {
		logger.Debug("Rolling back TX batch with timestamp: %v", timestamp)
		i.stack.RollbackTxBatch(timestamp)
		return fmt.Errorf("Fail to execute transactions: %v", err)
	}
	if logger.IsEnabledFor(logging.DEBUG) {
		logger.Debug("Committing TX batch with timestamp: %v", timestamp)
	}
	if _, err := i.stack.CommitTxBatch(timestamp, nil); err != nil {
		logger.Debug("Rolling back TX batch with timestamp: %v", timestamp)
		i.stack.RollbackTxBatch(timestamp)
		return err
	}
	return nil
}
Пример #5
0
func (i *Noops) notifyBlockAdded(block *pb.Block, delta *statemgmt.StateDelta) error {
	//make Payload nil to reduce block size..
	//anything else to remove .. do we need StateDelta ?
	for _, tx := range block.Transactions {
		tx.Payload = nil
	}
	data, err := proto.Marshal(&pb.BlockState{Block: block, StateDelta: delta.Marshal()})
	if err != nil {
		return fmt.Errorf("Fail to marshall BlockState structure: %v", err)
	}
	if logger.IsEnabledFor(logging.DEBUG) {
		logger.Debug("Broadcasting OpenchainMessage_SYNC_BLOCK_ADDED to non-validators")
	}

	// Broadcast SYNC_BLOCK_ADDED to connected NVPs
	// VPs already know about this newly added block since they participate
	// in the execution. That is, they can compare their current block with
	// the network block
	msg := &pb.OpenchainMessage{Type: pb.OpenchainMessage_SYNC_BLOCK_ADDED,
		Payload: data, Timestamp: util.CreateUtcTimestamp()}
	if errs := i.stack.Broadcast(msg, pb.PeerEndpoint_NON_VALIDATOR); nil != errs {
		return fmt.Errorf("Failed to broadcast with errors: %v", errs)
	}
	return nil
}
Пример #6
0
// NewChaincodeDeployTransaction is used to deploy chaincode.
func NewChaincodeDeployTransaction(chaincodeDeploymentSpec *ChaincodeDeploymentSpec, uuid string) (*Transaction, error) {
	transaction := new(Transaction)
	transaction.Type = Transaction_CHAINCODE_NEW
	transaction.Uuid = uuid
	transaction.Timestamp = util.CreateUtcTimestamp()
	cID := chaincodeDeploymentSpec.ChaincodeSpec.GetChaincodeID()
	if cID != nil {
		data, err := proto.Marshal(cID)
		if err != nil {
			return nil, fmt.Errorf("Could not marshal chaincode : %s", err)
		}
		transaction.ChaincodeID = data
	}
	//if chaincodeDeploymentSpec.ChaincodeSpec.GetCtorMsg() != nil {
	//	transaction.Function = chaincodeDeploymentSpec.ChaincodeSpec.GetCtorMsg().Function
	//	transaction.Args = chaincodeDeploymentSpec.ChaincodeSpec.GetCtorMsg().Args
	//}
	data, err := proto.Marshal(chaincodeDeploymentSpec)
	if err != nil {
		logger.Error(fmt.Sprintf("Error mashalling payload for chaincode deployment: %s", err))
		return nil, fmt.Errorf("Could not marshal payload for chaincode deployment: %s", err)
	}
	transaction.Payload = data
	return transaction, nil
}
Пример #7
0
// NewTransaction creates a new transaction. It defines the function to call,
// the chaincodeID on which the function should be called, and the arguments
// string. The arguments could be a string of JSON, but there is no strict
// requirement.
func NewTransaction(chaincodeID ChaincodeID, uuid string, function string, arguments []string) (*Transaction, error) {
	data, err := proto.Marshal(&chaincodeID)
	if err != nil {
		return nil, fmt.Errorf("Could not marshal chaincode : %s", err)
	}
	transaction := new(Transaction)
	transaction.ChaincodeID = data
	transaction.Uuid = uuid
	transaction.Timestamp = util.CreateUtcTimestamp()
	/*
		// Build the spec
		spec := &pb.ChaincodeSpec{Type: pb.ChaincodeSpec_GOLANG,
			ChaincodeID: chaincodeID, ChaincodeInput: &pb.ChaincodeInput{Function: function, Args: arguments}}

		// Build the ChaincodeInvocationSpec message
		invocation := &pb.ChaincodeInvocationSpec{ChaincodeSpec: spec}

		data, err := proto.Marshal(invocation)
		if err != nil {
			return nil, fmt.Errorf("Could not marshal payload for chaincode invocation: %s", err)
		}
		transaction.Payload = data
	*/
	return transaction, nil
}
Пример #8
0
// NewChaincodeExecute is used to deploy chaincode.
func NewChaincodeExecute(chaincodeInvocationSpec *ChaincodeInvocationSpec, uuid string, typ Transaction_Type) (*Transaction, error) {
	transaction := new(Transaction)
	transaction.Type = typ
	transaction.Uuid = uuid
	transaction.Timestamp = util.CreateUtcTimestamp()
	transaction.ChaincodeID = chaincodeInvocationSpec.ChaincodeSpec.GetChaincodeID()
	data, err := proto.Marshal(chaincodeInvocationSpec)
	if err != nil {
		return nil, fmt.Errorf("Could not marshal payload for chaincode invocation: %s", err)
	}
	transaction.Payload = data
	return transaction, nil
}
Пример #9
0
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")
	}
}
Пример #10
0
func (i *Noops) notifyBlockAdded() error {
	ledger, err := ledger.GetLedger()
	if err != nil {
		return fmt.Errorf("Fail to get the ledger: %v", err)
	}

	// TODO: Broadcast SYNC_BLOCK_ADDED to connected NVPs
	// VPs already know about this newly added block since they participate
	// in the execution. That is, they can compare their current block with
	// the network block
	// For now, send to everyone until broadcast has better discrimination
	blockHeight := ledger.GetBlockchainSize()
	logger.Debug("Preparing to broadcast with block number %v", blockHeight)
	block, err := ledger.GetBlockByNumber(blockHeight - 1)
	if nil != err {
		return err
	}
	//delta, err := ledger.GetStateDeltaBytes(blockHeight)
	delta, err := ledger.GetStateDelta(blockHeight - 1)
	if nil != err {
		return err
	}

	logger.Debug("Got the delta state of block number %v", blockHeight)
	data, err := proto.Marshal(&pb.BlockState{Block: block, StateDelta: delta.Marshal()})
	if err != nil {
		return fmt.Errorf("Fail to marshall BlockState structure: %v", err)
	}

	logger.Debug("Broadcasting OpenchainMessage_SYNC_BLOCK_ADDED")
	msg := &pb.OpenchainMessage{Type: pb.OpenchainMessage_SYNC_BLOCK_ADDED,
		Payload: data, Timestamp: util.CreateUtcTimestamp()}
	if errs := i.cpi.Broadcast(msg); nil != errs {
		return fmt.Errorf("Failed to broadcast with errors: %v", errs)
	}
	return nil
}
Пример #11
0
// NewOpenchainDiscoveryHello constructs a new HelloMessage for sending
func (p *PeerImpl) NewOpenchainDiscoveryHello() (*pb.OpenchainMessage, error) {
	helloMessage, err := p.newHelloMessage()
	if err != nil {
		return nil, fmt.Errorf("Error getting new HelloMessage: %s", err)
	}
	data, err := proto.Marshal(helloMessage)
	if err != nil {
		return nil, fmt.Errorf("Error marshalling HelloMessage: %s", err)
	}
	return &pb.OpenchainMessage{Type: pb.OpenchainMessage_DISC_HELLO, Payload: data, Timestamp: util.CreateUtcTimestamp()}, nil
}
Пример #12
0
// NewOpenchainDiscoveryHello constructs a new HelloMessage for sending
func (p *PeerImpl) NewOpenchainDiscoveryHello() (*pb.OpenchainMessage, error) {
	helloMessage, err := p.newHelloMessage()
	if err != nil {
		return nil, fmt.Errorf("Error getting new HelloMessage: %s", err)
	}
	data, err := proto.Marshal(helloMessage)
	if err != nil {
		return nil, fmt.Errorf("Error marshalling HelloMessage: %s", err)
	}
	// Need to sign the Discovery Hello message
	newDiscoveryHelloMsg := &pb.OpenchainMessage{Type: pb.OpenchainMessage_DISC_HELLO, Payload: data, Timestamp: util.CreateUtcTimestamp()}
	p.signOpenchainMessageMutating(newDiscoveryHelloMsg)
	return newDiscoveryHelloMsg, nil
}
Пример #13
0
// SendTransactionsToPeer current temporary mechanism of forwarding transactions to the configured Validator.
func (p *PeerImpl) SendTransactionsToPeer(peerAddress string, transaction *pb.Transaction) *pb.Response {
	conn, err := NewPeerClientConnectionWithAddress(peerAddress)
	if err != nil {
		return &pb.Response{Status: pb.Response_FAILURE, Msg: []byte(fmt.Sprintf("Error creating client to peer address=%s:  %s", peerAddress, err))}
	}
	defer conn.Close()
	serverClient := pb.NewPeerClient(conn)
	stream, err := serverClient.Chat(context.Background())
	if err != nil {
		return &pb.Response{Status: pb.Response_FAILURE, Msg: []byte(fmt.Sprintf("Error opening chat stream to peer address=%s:  %s", peerAddress, err))}
	}

	peerLogger.Debug("Sending HELLO to Peer: %s", peerAddress)

	helloMessage, err := p.NewOpenchainDiscoveryHello()
	if err != nil {
		return &pb.Response{Status: pb.Response_FAILURE, Msg: []byte(fmt.Sprintf("Unexpected error creating new HelloMessage (%s):  %s", peerAddress, err))}
	}
	if err = stream.Send(helloMessage); err != nil {
		stream.CloseSend()
		return &pb.Response{Status: pb.Response_FAILURE, Msg: []byte(fmt.Sprintf("Error sending hello to peer address=%s:  %s", peerAddress, err))}
	}

	waitc := make(chan struct{})
	var response *pb.Response
	go func() {
		// Make sure to close the wait channel
		defer close(waitc)
		expectHello := true
		for {
			in, err := stream.Recv()
			if err == io.EOF {
				peerLogger.Debug("Received EOF")
				// read done.
				if response == nil {
					response = &pb.Response{Status: pb.Response_FAILURE, Msg: []byte(fmt.Sprintf("Error sending transactions to peer address=%s, received EOF when expecting %s", peerAddress, pb.OpenchainMessage_DISC_HELLO))}
				}
				return
			}
			if err != nil {
				response = &pb.Response{Status: pb.Response_FAILURE, Msg: []byte(fmt.Sprintf("Unexpected error receiving on stream from peer (%s):  %s", peerAddress, err))}
				return
			}
			if in.Type == pb.OpenchainMessage_DISC_HELLO {
				expectHello = false

				peerLogger.Debug("Received %s message as expected, sending transaction...", in.Type)
				payload, err := proto.Marshal(transaction)
				if err != nil {
					response = &pb.Response{Status: pb.Response_FAILURE, Msg: []byte(fmt.Sprintf("Error marshalling transaction to peer address=%s:  %s", peerAddress, err))}
					return
				}

				var ttyp pb.OpenchainMessage_Type
				if transaction.Type == pb.Transaction_CHAINCODE_EXECUTE || transaction.Type == pb.Transaction_CHAINCODE_NEW {
					ttyp = pb.OpenchainMessage_CHAIN_TRANSACTION
				} else {
					ttyp = pb.OpenchainMessage_CHAIN_QUERY
				}

				msg := &pb.OpenchainMessage{Type: ttyp, Payload: payload, Timestamp: util.CreateUtcTimestamp()}
				peerLogger.Debug("Sending message %s with timestamp %v to Peer %s", msg.Type, msg.Timestamp, peerAddress)
				if err = stream.Send(msg); err != nil {
					peerLogger.Error(fmt.Sprintf("Error sending message %s with timestamp %v to Peer %s:  %s", msg.Type, msg.Timestamp, peerAddress, err))
				}
				//we are done with all our sends.... trigger stream close
				stream.CloseSend()
			} else if in.Type == pb.OpenchainMessage_RESPONSE {
				peerLogger.Debug("Received %s message as expected, will wait for EOF", in.Type)
				response = &pb.Response{}
				err = proto.Unmarshal(in.Payload, response)
				if err != nil {
					response = &pb.Response{Status: pb.Response_FAILURE, Msg: []byte(fmt.Sprintf("Error unpacking Payload from %s message: %s", pb.OpenchainMessage_CONSENSUS, err))}
				}

				//this should never happen but has to be tested (perhaps panic ?).
				//if we did get an out-of-band Response, CloseSend as we may not get a DISC_HELLO
				if expectHello {
					peerLogger.Error(fmt.Sprintf("Received unexpected %s message, will wait for EOF", in.Type))
					stream.CloseSend()
				}
			} else {
				peerLogger.Debug("Got unexpected message %s, with bytes length = %d,  doing nothing", in.Type, len(in.Payload))
			}
		}
	}()

	//TODO Timeout handling
	<-waitc
	return response
}