github.com/annchain/OG@v0.0.9/og/verifier/graph_verifier.go (about)

     1  package verifier
     2  
     3  import (
     4  	types2 "github.com/annchain/OG/arefactor/og/types"
     5  	"github.com/annchain/OG/og"
     6  	"github.com/annchain/OG/og/protocol/ogmessage/archive"
     7  	"github.com/annchain/OG/og/types"
     8  	"github.com/annchain/OG/ogcore/pool"
     9  
    10  	"github.com/annchain/OG/status"
    11  	"github.com/sirupsen/logrus"
    12  )
    13  
    14  // GraphVerifier verifies if the tx meets the OG hash and graph standards.
    15  type GraphVerifier struct {
    16  	Dag    og.IDag
    17  	TxPool pool.ITxPool
    18  	//Buffer *TxBuffer
    19  }
    20  
    21  func (c *GraphVerifier) String() string {
    22  	return c.Name()
    23  }
    24  func (v *GraphVerifier) Independent() bool {
    25  	return false
    26  }
    27  
    28  func (v *GraphVerifier) Name() string {
    29  	return "GraphVerifier"
    30  }
    31  
    32  // getTxFromTempSource tries to get tx from anywhere but dag itself.
    33  // return nil if not found in either txpool or buffer
    34  func (v *GraphVerifier) getTxFromTempSource(hash types2.Hash) (txi types.Txi) {
    35  	// Re-think. Do we really need to check buffer?
    36  
    37  	//if v.Buffer != nil {
    38  	//	txi = v.Buffer.GetFromBuffer(hash)
    39  	//	if txi != nil {
    40  	//		return
    41  	//	}
    42  	//}
    43  
    44  	if v.TxPool != nil {
    45  		txi = v.TxPool.Get(hash)
    46  		if txi != nil {
    47  			return
    48  		}
    49  	}
    50  	return
    51  }
    52  
    53  func (v *GraphVerifier) getTxFromAnywhere(hash types2.Hash) (txi types.Txi, archived bool) {
    54  	txi = v.getTxFromTempSource(hash)
    55  	if txi != nil {
    56  		archived = false
    57  		return
    58  	}
    59  	if v.Dag != nil {
    60  		txi = v.Dag.GetTx(hash)
    61  		if txi != nil {
    62  			archived = true
    63  			return
    64  		}
    65  	}
    66  	return
    67  }
    68  
    69  // getMyPreviousTx tries to fetch the tx that is announced by the same source with nonce = current nonce -1
    70  // return true if found, or false if not found in txpool or in dag
    71  func (v *GraphVerifier) getMyPreviousTx(currentTx types.Txi) (previousTx types.Txi, ok bool) {
    72  	if currentTx.GetNonce() == 1 {
    73  		ok = true
    74  		return
    75  	}
    76  	seeked := map[types2.Hash]bool{}
    77  	seekingHashes := types2.Hashes{}
    78  	for _, parent := range currentTx.GetParents() {
    79  		seekingHashes = append(seekingHashes, parent)
    80  	}
    81  
    82  	if status.ArchiveMode {
    83  		if ptx := v.Dag.GetTxByNonce(currentTx.Sender(), currentTx.GetNonce()-1); ptx != nil {
    84  			previousTx = ptx
    85  			ok = true
    86  			return
    87  		}
    88  		return nil, false
    89  	}
    90  
    91  	for len(seekingHashes) > 0 {
    92  		head := seekingHashes[0]
    93  		seekingHashes = seekingHashes[1:]
    94  
    95  		txi, archived := v.getTxFromAnywhere(head)
    96  		if txi != nil {
    97  			// found. verify nonce
    98  			if txi.GetType() != types.TxBaseTypeArchive {
    99  				if txi.Sender() == currentTx.Sender() {
   100  					// verify if the nonce is larger
   101  					if txi.GetNonce() == currentTx.GetNonce()-1 {
   102  						// good
   103  						previousTx = txi
   104  						ok = true
   105  						return
   106  					}
   107  				}
   108  			}
   109  
   110  			switch txi.GetType() {
   111  			case types.TxBaseTypeSequencer:
   112  				// nothing to do, since all txs before seq should already be archived
   113  			default:
   114  				// may be somewhere else
   115  				// enqueue header more if we are still in the temp area
   116  				if archived {
   117  					continue
   118  				}
   119  				for _, parent := range txi.GetParents() {
   120  					if _, ok := seeked[parent]; !ok {
   121  						seekingHashes = append(seekingHashes, parent)
   122  						seeked[parent] = true
   123  					}
   124  				}
   125  				continue
   126  
   127  			}
   128  		} else {
   129  			// should not be here
   130  			logrus.WithField("current tx ", currentTx).WithField("ancestor", head).Warn("ancestor not found: should not be here.")
   131  			// this ancestor should already be in the dag. do nothing
   132  		}
   133  	}
   134  
   135  	//// Here, the ancestor of the same From address must be in the dag.
   136  	//// Once found, this tx must be the previous tx of currentTx because everyone behind sequencer is confirmed by sequencer
   137  	//if ptx := v.Dag.GetTxByNonce(currentTx.Sender(), currentTx.GetNonce()-1); ptx != nil {
   138  	//	previousTx = ptx
   139  	//	ok = true
   140  	//	return
   141  	//}
   142  	//return
   143  	return
   144  }
   145  
   146  // get the nearest previous sequencer from txpool
   147  func (v *GraphVerifier) getPreviousSequencer(currentSeq *types.Sequencer) (previousSeq *types.Sequencer, ok bool) {
   148  	seeked := map[types2.Hash]bool{}
   149  	seekingHashes := types2.Hashes{}
   150  	// seekingHashes := list.New()
   151  	seekingHashes = append(seekingHashes, currentSeq.GetHash())
   152  	// seekingHashes.PushBack(currentSeq.GetHash())
   153  	for len(seekingHashes) > 0 {
   154  		head := seekingHashes[0]
   155  		seekingHashes = seekingHashes[1:]
   156  		// head := seekingHashes.Remove(seekingHashes.Front()).(common.Hash)
   157  		txi, archived := v.getTxFromAnywhere(head)
   158  
   159  		if txi != nil {
   160  			switch txi.GetType() {
   161  			case types.TxBaseTypeSequencer:
   162  				// found seq, check nonce
   163  				// verify if the nonce is larger
   164  				if txi.(*types.Sequencer).Height == currentSeq.Height-1 {
   165  					// good
   166  					previousSeq = txi.(*types.Sequencer)
   167  					ok = true
   168  					return
   169  				}
   170  			default:
   171  				break
   172  			}
   173  			// may be somewhere else
   174  			// enqueue header more if we are still in the temp area
   175  			if archived {
   176  				continue
   177  			}
   178  			for _, parent := range txi.GetParents() {
   179  				if _, ok := seeked[parent]; !ok {
   180  					seekingHashes = append(seekingHashes, parent)
   181  					// seekingHashes.PushBack(parent)
   182  					seeked[parent] = true
   183  				}
   184  			}
   185  		}
   186  	}
   187  	// Here, the ancestor of the same From address must be in the dag.
   188  	// Once found, this tx must be the previous tx of currentTx because everyone behind sequencer is confirmed by sequencer
   189  	if ptx := v.Dag.GetSequencerByHeight(currentSeq.Height - 1); ptx != nil {
   190  		previousSeq = ptx
   191  		ok = true
   192  		return
   193  	} else {
   194  		logrus.Debug(ptx, currentSeq.Height-1)
   195  	}
   196  
   197  	return
   198  }
   199  
   200  // Verify do the graph validation according to the following rules that are marked as [My job].
   201  // Graph standards:
   202  // A1: [My job] Randomly choose 2 tips.
   203  // A2: [Not used] Node's parent cannot be its grandparents or ancestors.
   204  // A3: [My job] Nodes produced by same source must be sequential (tx nonce ++).
   205  // A4: [------] Double spending once A3 is not followed, whatever there is actual double spending.
   206  // A5: [Pool's job] If A3 is followed but there is still double spending (tx nonce collision), keep the forked tx with smaller hash
   207  // A6: [My job] Node cannot reference two un-ordered nodes as its parents
   208  // B1: [My job] Nodes that are confirmed by at least N (=2) sequencers cannot be referenced.
   209  // B2: [My job] Two layer hash validation
   210  // Basically Verify checks whether txs are in their nonce order
   211  func (v *GraphVerifier) Verify(txi types.Txi) (ok bool) {
   212  	//if txi.IsVerified().IsGraphVerified() {
   213  	//	return true
   214  	//}
   215  	ok = false
   216  	if ok = v.verifyWeight(txi); !ok {
   217  		logrus.WithField("tx", txi).Debug("tx failed on weight")
   218  		return
   219  	}
   220  	if ok = v.verifyA3(txi); !ok {
   221  		logrus.WithField("tx", txi).Debug("tx failed on graph A3")
   222  		return
   223  	}
   224  	if ok = v.verifyB1(txi); !ok {
   225  		logrus.WithField("tx", txi).Debug("tx failed on graph B1")
   226  		return
   227  	}
   228  	if txi.GetType() == types.TxBaseTypeSequencer {
   229  		seq := txi.(*types.Sequencer)
   230  		if err := v.TxPool.IsBadSeq(seq); err != nil {
   231  			logrus.WithField("seq ", seq).WithError(err).Warn("bad seq")
   232  			return false
   233  		}
   234  	}
   235  
   236  	txi.SetVerified(archive.VerifiedGraph)
   237  	return true
   238  }
   239  
   240  func (v *GraphVerifier) verifyA3(txi types.Txi) bool {
   241  	// constantly check the ancestors until the same one issued by me is found.
   242  	// or nonce reaches 1
   243  
   244  	if txi.GetType() == types.TxBaseTypeArchive {
   245  		return true
   246  	}
   247  	if status.ArchiveMode {
   248  		if txi.GetType() != types.TxBaseTypeSequencer {
   249  			logrus.Warn("archive mode , only process archive")
   250  			return false
   251  		}
   252  	}
   253  
   254  	if txi.GetNonce() == 0 {
   255  		return false
   256  	}
   257  	var ok bool
   258  
   259  	// first tx check
   260  	nonce, poolErr := v.TxPool.GetLatestNonce(txi.Sender())
   261  	if txi.GetNonce() == 1 {
   262  		// test claim: whether it should be 0
   263  
   264  		if poolErr == nil {
   265  			logrus.Debugf("nonce should not be 0. Latest nonce is %d and you should be larger than it", nonce)
   266  		}
   267  		// not found is good
   268  		return poolErr != nil
   269  	}
   270  	dagNonce, _ := v.Dag.GetLatestNonce(txi.Sender())
   271  	if poolErr != nil {
   272  		//no related tx in txpool ,check dag
   273  		if dagNonce != txi.GetNonce()-1 {
   274  			logrus.WithField("current nonce ", txi.GetNonce()).WithField("dag nonce ", dagNonce).WithField("tx", txi).Debug("previous tx  not found for address")
   275  			// fail if not good
   276  			return false
   277  		}
   278  		goto Out
   279  	}
   280  	if nonce < txi.GetNonce()-1 {
   281  		logrus.WithField("current nonce ", txi.GetNonce()).WithField("pool nonce ", nonce).WithField("tx", txi).Debug("previous tx  not found for address")
   282  		// fail if not good
   283  		return false
   284  	}
   285  	// check txpool queue first
   286  	if dagNonce != nonce {
   287  		_, ok = v.getMyPreviousTx(txi)
   288  		if !ok {
   289  			logrus.WithField("tx", txi).Debug("previous tx not found")
   290  			// fail if not good
   291  			return ok
   292  		}
   293  	}
   294  
   295  Out:
   296  
   297  	switch txi.GetType() {
   298  	// no additional check
   299  	case types.TxBaseTypeSequencer:
   300  		seq := txi.(*types.Sequencer)
   301  		// to check if there is a lower seq height in the path behind
   302  		_, ok = v.getPreviousSequencer(seq)
   303  		if !ok {
   304  			logrus.WithField("tx", txi).Debug("previous seq not found")
   305  		}
   306  
   307  		return ok
   308  	default:
   309  	}
   310  	return true
   311  }
   312  
   313  func (v *GraphVerifier) verifyB1(txi types.Txi) bool {
   314  	// compare the sequencer id
   315  	return true
   316  }
   317  
   318  func (v *GraphVerifier) verifyWeight(txi types.Txi) bool {
   319  	var parents types.Txis
   320  	for _, pHash := range txi.GetParents() {
   321  		parent := v.TxPool.Get(pHash)
   322  		if parent == nil {
   323  			parent = v.Dag.GetTx(pHash)
   324  		}
   325  		if parent == nil {
   326  			logrus.WithField("parent hash ", pHash).Warn("parent not found")
   327  			return false
   328  		}
   329  		parents = append(parents, parent)
   330  	}
   331  	return txi.CalculateWeight(parents) == txi.GetWeight()
   332  }