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") } }
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 }
// 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 }
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 }
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 }
// 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 }
// 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 }
// 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 }
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") } }
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 }
// 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 }
// 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 }
// 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 }