github.com/inklabsfoundation/inkchain@v0.17.1-0.20181025012015-c3cef8062f19/orderer/ledger/util.go (about)

     1  /*
     2  Copyright IBM Corp. 2016 All Rights Reserved.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8                   http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package ledger
    18  
    19  import (
    20  	"github.com/golang/protobuf/proto"
    21  	"github.com/inklabsfoundation/inkchain/core/wallet"
    22  	cb "github.com/inklabsfoundation/inkchain/protos/common"
    23  	ab "github.com/inklabsfoundation/inkchain/protos/orderer"
    24  	putils "github.com/inklabsfoundation/inkchain/protos/utils"
    25  )
    26  
    27  var closedChan chan struct{}
    28  
    29  func init() {
    30  	closedChan = make(chan struct{})
    31  	close(closedChan)
    32  }
    33  
    34  // NotFoundErrorIterator simply always returns an error of cb.Status_NOT_FOUND,
    35  // and is generally useful for implementations of the Reader interface
    36  type NotFoundErrorIterator struct{}
    37  
    38  // Next returns nil, cb.Status_NOT_FOUND
    39  func (nfei *NotFoundErrorIterator) Next() (*cb.Block, cb.Status) {
    40  	return nil, cb.Status_NOT_FOUND
    41  }
    42  
    43  // ReadyChan returns a closed channel
    44  func (nfei *NotFoundErrorIterator) ReadyChan() <-chan struct{} {
    45  	return closedChan
    46  }
    47  
    48  // CreateNextBlock provides a utility way to construct the next block from
    49  // contents and metadata for a given ledger
    50  // XXX This will need to be modified to accept marshaled envelopes
    51  //     to accommodate non-deterministic marshaling
    52  func CreateNextBlock(rl Reader, messages []*cb.Envelope, feeAddress string, blockVersion uint64) *cb.Block {
    53  	var nextBlockNumber uint64
    54  	var previousBlockHash []byte
    55  
    56  	if rl.Height() > 0 {
    57  		it, _ := rl.Iterator(&ab.SeekPosition{
    58  			Type: &ab.SeekPosition_Newest{
    59  				&ab.SeekNewest{},
    60  			},
    61  		})
    62  		<-it.ReadyChan() // Should never block, but just in case
    63  		block, status := it.Next()
    64  		if status != cb.Status_SUCCESS {
    65  			panic("Error seeking to newest block for chain with non-zero height")
    66  		}
    67  		nextBlockNumber = block.Header.Number + 1
    68  		previousBlockHash = block.Header.Hash()
    69  	}
    70  	// bubble sort transactions by sender counter
    71  	tx_number := len(messages)
    72  	txOrder := make([]int, tx_number)
    73  	txCounter := make([]uint64, tx_number)
    74  	var j, i int
    75  	for i, msg := range messages {
    76  		txOrder[i] = i
    77  		cis, _, err := putils.GetActionFromEnvelopePayload(msg.Payload)
    78  		if err != nil || cis.SenderSpec == nil {
    79  			txCounter[i] = 0
    80  		} else {
    81  			txCounter[i] = cis.SenderSpec.Counter
    82  		}
    83  	}
    84  	var temp uint64
    85  	var temp_idx int
    86  	for i = tx_number - 1; i > 0; i-- {
    87  		for j = tx_number - 1; j > tx_number-1-i; j-- {
    88  			if txCounter[j] < txCounter[j-1] {
    89  				temp = txCounter[j]
    90  				txCounter[j] = txCounter[j-1]
    91  				txCounter[j-1] = temp
    92  				temp_idx = txOrder[j]
    93  				txOrder[j] = txOrder[j-1]
    94  				txOrder[j-1] = temp_idx
    95  			}
    96  		}
    97  	}
    98  	data := &cb.BlockData{
    99  		Data: make([][]byte, tx_number),
   100  	}
   101  	var err error
   102  	for i, j := range txOrder {
   103  		data.Data[i], err = proto.Marshal(messages[j])
   104  		if err != nil {
   105  			panic(err)
   106  		}
   107  	}
   108  	block := cb.NewBlock(nextBlockNumber, previousBlockHash, wallet.StringToAddress(feeAddress).ToBytes(), blockVersion)
   109  	block.Header.DataHash = data.Hash()
   110  	block.Data = data
   111  
   112  	return block
   113  }
   114  
   115  // GetBlock is a utility method for retrieving a single block
   116  func GetBlock(rl Reader, index uint64) *cb.Block {
   117  	i, _ := rl.Iterator(&ab.SeekPosition{
   118  		Type: &ab.SeekPosition_Specified{
   119  			Specified: &ab.SeekSpecified{Number: index},
   120  		},
   121  	})
   122  	select {
   123  	case <-i.ReadyChan():
   124  		block, status := i.Next()
   125  		if status != cb.Status_SUCCESS {
   126  			return nil
   127  		}
   128  		return block
   129  	default:
   130  		return nil
   131  	}
   132  }