github.com/braveheart12/just@v0.8.7/pulsar/pulsarconsensus.go (about)

     1  /*
     2   *    Copyright 2019 Insolar Technologies
     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 pulsar
    18  
    19  import (
    20  	"context"
    21  	"crypto"
    22  	"sync"
    23  
    24  	"github.com/insolar/insolar/core"
    25  	"github.com/insolar/insolar/instrumentation/inslogger"
    26  	"github.com/insolar/insolar/instrumentation/instracer"
    27  	"github.com/pkg/errors"
    28  )
    29  
    30  // SetBftGridItem set item of the bftGrid in the thread-safe way
    31  func (currentPulsar *Pulsar) SetBftGridItem(key string, value map[string]*BftCell) {
    32  	currentPulsar.BftGridLock.Lock()
    33  	currentPulsar.bftGrid[key] = value
    34  	defer currentPulsar.BftGridLock.Unlock()
    35  }
    36  
    37  // GetBftGridItem returns a grid item i nthe thread-safe way
    38  func (currentPulsar *Pulsar) GetBftGridItem(row string, column string) *BftCell {
    39  	currentPulsar.BftGridLock.RLock()
    40  	defer currentPulsar.BftGridLock.RUnlock()
    41  	return currentPulsar.bftGrid[row][column]
    42  }
    43  
    44  // BftCell is a cell in NxN btf-grid
    45  type BftCell struct {
    46  	signLock              sync.RWMutex
    47  	entropyLock           sync.RWMutex
    48  	isEntropyReceivedLock sync.RWMutex
    49  
    50  	Sign              []byte
    51  	Entropy           core.Entropy
    52  	IsEntropyReceived bool
    53  }
    54  
    55  // SetSign sets Sign in the thread-safe way
    56  func (bftCell *BftCell) SetSign(sign []byte) {
    57  	bftCell.signLock.Lock()
    58  	defer bftCell.signLock.Unlock()
    59  	bftCell.Sign = sign
    60  }
    61  
    62  // GetSign gets Sign in the thread-safe way
    63  func (bftCell *BftCell) GetSign() []byte {
    64  	bftCell.signLock.RLock()
    65  	defer bftCell.signLock.RUnlock()
    66  	return bftCell.Sign
    67  }
    68  
    69  // SetEntropy sets Entropy in the thread-safe way
    70  func (bftCell *BftCell) SetEntropy(entropy core.Entropy) {
    71  	bftCell.entropyLock.Lock()
    72  	defer bftCell.entropyLock.Unlock()
    73  	bftCell.Entropy = entropy
    74  }
    75  
    76  // GetEntropy gets Entropy in the thread-safe way
    77  func (bftCell *BftCell) GetEntropy() core.Entropy {
    78  	bftCell.entropyLock.RLock()
    79  	defer bftCell.entropyLock.RUnlock()
    80  	return bftCell.Entropy
    81  }
    82  
    83  // SetIsEntropyReceived sets IsEntropyReceived in the thread-safe way
    84  func (bftCell *BftCell) SetIsEntropyReceived(isEntropyReceived bool) {
    85  	bftCell.isEntropyReceivedLock.Lock()
    86  	defer bftCell.isEntropyReceivedLock.Unlock()
    87  	bftCell.IsEntropyReceived = isEntropyReceived
    88  }
    89  
    90  // GetIsEntropyReceived gets IsEntropyReceived in the thread-safe way
    91  func (bftCell *BftCell) GetIsEntropyReceived() bool {
    92  	bftCell.isEntropyReceivedLock.RLock()
    93  	defer bftCell.isEntropyReceivedLock.RUnlock()
    94  	return bftCell.IsEntropyReceived
    95  }
    96  
    97  func (currentPulsar *Pulsar) verify(ctx context.Context) {
    98  	ctx, span := instracer.StartSpan(ctx, "Pulsar.verify")
    99  	defer span.End()
   100  
   101  	logger := inslogger.FromContext(ctx)
   102  	logger.Debugf("[verify] - %v", currentPulsar.Config.MainListenerAddress)
   103  
   104  	if currentPulsar.IsStateFailed() {
   105  		return
   106  
   107  	}
   108  	if currentPulsar.isStandalone() {
   109  		currentPulsar.SetCurrentSlotEntropy(currentPulsar.GetGeneratedEntropy())
   110  		currentPulsar.CurrentSlotPulseSender = currentPulsar.PublicKeyRaw
   111  		currentPulsar.StateSwitcher.SwitchToState(ctx, SendingPulse, nil)
   112  		return
   113  	}
   114  
   115  	type bftMember struct {
   116  		PubPem string
   117  		PubKey crypto.PublicKey
   118  	}
   119  
   120  	var finalEntropySet []core.Entropy
   121  
   122  	keys := []string{currentPulsar.PublicKeyRaw}
   123  	activePulsars := []*bftMember{{currentPulsar.PublicKeyRaw, currentPulsar.PublicKey}}
   124  	for key, neighbour := range currentPulsar.Neighbours {
   125  		activePulsars = append(activePulsars, &bftMember{key, neighbour.PublicKey})
   126  		keys = append(keys, key)
   127  	}
   128  
   129  	// Check NxN consensus-matrix
   130  	wrongVectors := 0
   131  	for _, column := range activePulsars {
   132  		currentColumnStat := map[string]int{}
   133  		for _, row := range activePulsars {
   134  			bftCell := currentPulsar.GetBftGridItem(row.PubPem, column.PubPem)
   135  
   136  			if bftCell == nil {
   137  				currentColumnStat["nil"]++
   138  				continue
   139  			}
   140  
   141  			publicKey, err := currentPulsar.KeyProcessor.ImportPublicKeyPEM([]byte(column.PubPem))
   142  			if err != nil {
   143  				currentColumnStat["nil"]++
   144  				continue
   145  			}
   146  
   147  			entropy := bftCell.GetEntropy()
   148  			ok := currentPulsar.CryptographyService.Verify(publicKey, core.SignatureFromBytes(bftCell.GetSign()), entropy[:])
   149  			if !ok {
   150  				currentColumnStat["nil"]++
   151  				continue
   152  			}
   153  
   154  			currentColumnStat[string(entropy[:])]++
   155  		}
   156  
   157  		maxConfirmationsForEntropy := int(0)
   158  		var chosenEntropy core.Entropy
   159  		for key, value := range currentColumnStat {
   160  			if value > maxConfirmationsForEntropy && key != "nil" {
   161  				maxConfirmationsForEntropy = value
   162  				copy(chosenEntropy[:], []byte(key)[:core.EntropySize])
   163  			}
   164  		}
   165  
   166  		if maxConfirmationsForEntropy >= currentPulsar.getMinimumNonTraitorsCount() {
   167  			finalEntropySet = append(finalEntropySet, chosenEntropy)
   168  		} else {
   169  			wrongVectors++
   170  		}
   171  	}
   172  
   173  	if len(finalEntropySet) == 0 || wrongVectors > currentPulsar.getMaxTraitorsCount() {
   174  		currentPulsar.StateSwitcher.SwitchToState(
   175  			ctx,
   176  			Failed,
   177  			errors.Errorf("bft is broken. len(finalEntropySet) == %v, wrongVectors - %v", len(finalEntropySet), wrongVectors),
   178  		)
   179  		return
   180  	}
   181  
   182  	var finalEntropy core.Entropy
   183  
   184  	for _, tempEntropy := range finalEntropySet {
   185  		for byteIndex := 0; byteIndex < core.EntropySize; byteIndex++ {
   186  			finalEntropy[byteIndex] ^= tempEntropy[byteIndex]
   187  		}
   188  	}
   189  	currentPulsar.finalizeBft(ctx, finalEntropy, keys)
   190  }
   191  
   192  func (currentPulsar *Pulsar) finalizeBft(ctx context.Context, finalEntropy core.Entropy, activePulsars []string) {
   193  	ctx, span := instracer.StartSpan(ctx, "Pulsar.finalizeBft")
   194  	defer span.End()
   195  
   196  	currentPulsar.SetCurrentSlotEntropy(&finalEntropy)
   197  	chosenPulsar, err := selectByEntropy(
   198  		currentPulsar.PlatformCryptographyScheme, finalEntropy, activePulsars, 1)
   199  	if err != nil {
   200  		currentPulsar.StateSwitcher.SwitchToState(ctx, Failed, err)
   201  	}
   202  	currentPulsar.CurrentSlotPulseSender = chosenPulsar[0]
   203  	if currentPulsar.CurrentSlotPulseSender == currentPulsar.PublicKeyRaw {
   204  		//here confirmation myself
   205  		payload := PulseSenderConfirmationPayload{core.PulseSenderConfirmation{
   206  			ChosenPublicKey: currentPulsar.CurrentSlotPulseSender,
   207  			Entropy:         *currentPulsar.GetCurrentSlotEntropy(),
   208  			PulseNumber:     currentPulsar.ProcessingPulseNumber,
   209  		}}
   210  		hashProvider := currentPulsar.PlatformCryptographyScheme.IntegrityHasher()
   211  		hash, err := payload.Hash(hashProvider)
   212  		if err != nil {
   213  			currentPulsar.StateSwitcher.SwitchToState(ctx, Failed, err)
   214  			return
   215  		}
   216  		signature, err := currentPulsar.CryptographyService.Sign(hash)
   217  		if err != nil {
   218  			currentPulsar.StateSwitcher.SwitchToState(ctx, Failed, err)
   219  			return
   220  		}
   221  
   222  		currentPulsar.currentSlotSenderConfirmationsLock.Lock()
   223  		currentPulsar.CurrentSlotSenderConfirmations[currentPulsar.PublicKeyRaw] = core.PulseSenderConfirmation{
   224  			ChosenPublicKey: currentPulsar.CurrentSlotPulseSender,
   225  			Signature:       signature.Bytes(),
   226  			Entropy:         *currentPulsar.GetCurrentSlotEntropy(),
   227  			PulseNumber:     currentPulsar.ProcessingPulseNumber,
   228  		}
   229  		currentPulsar.currentSlotSenderConfirmationsLock.Unlock()
   230  
   231  		currentPulsar.StateSwitcher.SwitchToState(ctx, WaitingForPulseSigns, nil)
   232  	} else {
   233  		currentPulsar.StateSwitcher.SwitchToState(ctx, SendingPulseSign, nil)
   234  	}
   235  }