github.com/cranelv/ethereum_mpc@v0.0.0-20191031014521-23aeb1415092/consensus_pbft/executor/executor.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 executor
    18  
    19  import (
    20  	"github.com/ethereum/go-ethereum/consensus_pbft"
    21  	"github.com/ethereum/go-ethereum/consensus_pbft/util/events"
    22  
    23  	"github.com/ethereum/go-ethereum/consensus_pbft/consensusInterface"
    24  	"github.com/ethereum/go-ethereum/consensus_pbft/message"
    25  	"github.com/ethereum/go-ethereum/consensus_pbft/pbftTypes"
    26  	"github.com/ethereum/go-ethereum/consensus_pbft/singletons"
    27  )
    28  
    29  // PartialStack contains the ledger features required by the executor.Coordinator
    30  type PartialStack interface {
    31  	consensusInterface.NodeExecutor
    32  	GetStateInfo() *message.StateInfo
    33  }
    34  
    35  type coordinatorImpl struct {
    36  	manager         events.Manager              // Maintains event thread and sends events to the coordinator
    37  	rawExecutor     PartialStack                // Does the real interaction with the ledger
    38  	consumer        consensus_pbft.ExecutionConsumer // The consumer of this coordinator which receives the callbacks
    39  	stc             consensusInterface.Coordinator	// State transfer instance
    40  	batchInProgress bool                        // Are we mid execution batch
    41  	skipInProgress  bool                        // Are we mid state transfer
    42  }
    43  
    44  // NewCoordinatorImpl creates a new executor.Coordinator
    45  func NewImpl(consumer consensus_pbft.ExecutionConsumer, rawExecutor PartialStack) consensus_pbft.Executor {
    46  	co := &coordinatorImpl{
    47  		rawExecutor: rawExecutor,
    48  		consumer:    consumer,
    49  //		stc:         statetransfer.NewCoordinatorImpl(stps),
    50  		manager:     events.NewManagerImpl(),
    51  	}
    52  	co.manager.SetReceiver(co)
    53  	return co
    54  }
    55  
    56  // ProcessEvent is the main event loop for the executor.Coordinator
    57  func (co *coordinatorImpl) ProcessEvent(event events.Event) events.Event {
    58  	switch et := event.(type) {
    59  	case executeEvent:
    60  		singletons.Log.Debug("Executor is processing an executeEvent")
    61  		if co.skipInProgress {
    62  			singletons.Log.Error("FATAL programming error, attempted to execute a transaction during state transfer")
    63  			return nil
    64  		}
    65  
    66  		if !co.batchInProgress {
    67  			singletons.Log.Debug("Starting new transaction batch")
    68  			co.batchInProgress = true
    69  			err := co.rawExecutor.BeginTaskBatch(co)
    70  			_ = err // TODO This should probably panic, see issue 752
    71  		}
    72  
    73  		co.rawExecutor.ExecTasks(co, et.tasks)
    74  
    75  		co.consumer.Executed(et.tag)
    76  	case commitEvent:
    77  		singletons.Log.Debug("Executor is processing an commitEvent")
    78  		if co.skipInProgress {
    79  			singletons.Log.Error("Likely FATAL programming error, attempted to commit a transaction batch during state transfer")
    80  			return nil
    81  		}
    82  
    83  		if !co.batchInProgress {
    84  			singletons.Log.Error("Likely FATAL programming error, attemted to commit a transaction batch when one does not exist")
    85  			return nil
    86  		}
    87  
    88  		_, err := co.rawExecutor.CommitTaskBatch(co, et.metadata)
    89  		_ = err // TODO This should probably panic, see issue 752
    90  
    91  		co.batchInProgress = false
    92  
    93  		info := co.rawExecutor.GetStateInfo()
    94  
    95  		singletons.Log.Debugf("Committed tasksInfo with hash %x to chain", info.Digest())
    96  
    97  		co.consumer.Committed(et.tag, info)
    98  	case rollbackEvent:
    99  		singletons.Log.Debug("Executor is processing an rollbackEvent")
   100  		if co.skipInProgress {
   101  			singletons.Log.Error("Programming error, attempted to rollback a transaction batch during state transfer")
   102  			return nil
   103  		}
   104  
   105  		if !co.batchInProgress {
   106  			singletons.Log.Error("Programming error, attempted to rollback a transaction batch which had not started")
   107  			return nil
   108  		}
   109  
   110  		err := co.rawExecutor.RollbackTaskBatch(co)
   111  		_ = err // TODO This should probably panic, see issue 752
   112  
   113  		co.batchInProgress = false
   114  
   115  		co.consumer.RolledBack(et.tag)
   116  	case stateUpdateEvent:
   117  		singletons.Log.Debug("Executor is processing a stateUpdateEvent")
   118  		if co.batchInProgress {
   119  			err := co.rawExecutor.RollbackTaskBatch(co)
   120  			_ = err // TODO This should probably panic, see issue 752
   121  		}
   122  
   123  		co.skipInProgress = true
   124  
   125  		info := et.stateInfo
   126  		for {
   127  			err, recoverable := co.stc.SyncToTarget( info.Height(), info.Digest(), et.peers)
   128  			if err == nil {
   129  				singletons.Log.Debug("State transfer sync completed, returning")
   130  				co.skipInProgress = false
   131  				co.consumer.StateUpdated(et.tag, info)
   132  				return nil
   133  			}
   134  			if !recoverable {
   135  				singletons.Log.Warnf("State transfer failed irrecoverably, calling back to consumer: %s", err)
   136  				co.consumer.StateUpdated(et.tag, nil)
   137  				return nil
   138  			}
   139  			singletons.Log.Warnf("State transfer did not complete successfully but is recoverable, trying again: %s", err)
   140  			et.peers = nil // Broaden the peers included in recover to all connected
   141  		}
   142  	default:
   143  		singletons.Log.Error("Unknown event type %s", et)
   144  	}
   145  
   146  	return nil
   147  }
   148  
   149  // Commit commits whatever outstanding requests have been executed, it is an error to call this without pending executions
   150  func (co *coordinatorImpl) Commit(tag interface{}, metadata []byte) {
   151  	co.manager.Queue() <- commitEvent{tag, metadata}
   152  }
   153  
   154  // Execute adds additional executions to the current batch
   155  func (co *coordinatorImpl) Execute(tag interface{}, txs []*message.Task) {
   156  	co.manager.Queue() <- executeEvent{tag, txs}
   157  }
   158  
   159  // Rollback rolls back the executions from the current batch
   160  func (co *coordinatorImpl) Rollback(tag interface{}) {
   161  	co.manager.Queue() <- rollbackEvent{tag}
   162  }
   163  
   164  // UpdateState uses the state transfer subsystem to attempt to progress to a target
   165  func (co *coordinatorImpl) UpdateState(tag interface{}, info *message.StateInfo, peers []*pbftTypes.PeerID) {
   166  	co.manager.Queue() <- stateUpdateEvent{tag, info, peers}
   167  }
   168  
   169  // Start must be called before utilizing the Coordinator
   170  func (co *coordinatorImpl) Start() {
   171  	co.stc.Start()
   172  	co.manager.Start()
   173  }
   174  
   175  // Halt should be called to clean up resources allocated by the Coordinator
   176  func (co *coordinatorImpl) Halt() {
   177  	co.stc.Stop()
   178  	co.manager.Halt()
   179  }
   180  
   181  // Event types
   182  
   183  type executeEvent struct {
   184  	tag interface{}
   185  	tasks []*message.Task
   186  }
   187  
   188  // Note, this cannot be a simple type alias, in case tag is nil
   189  type rollbackEvent struct {
   190  	tag interface{}
   191  }
   192  
   193  type commitEvent struct {
   194  	tag      interface{}
   195  	metadata []byte
   196  }
   197  
   198  type stateUpdateEvent struct {
   199  	tag            interface{}
   200  	stateInfo 	   *message.StateInfo
   201  	peers          []*pbftTypes.PeerID
   202  }