github.com/annchain/OG@v0.0.9/og/txmaker/ogtx_creator.go (about)

     1  // Copyright © 2019 Annchain Authors <EMAIL ADDRESS>
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  package txmaker
    15  
    16  import (
    17  	"errors"
    18  	"fmt"
    19  	"github.com/annchain/OG/arefactor/common/goroutine"
    20  	types2 "github.com/annchain/OG/arefactor/og/types"
    21  	"github.com/annchain/OG/arefactor/og_interface"
    22  	"github.com/annchain/OG/common"
    23  	"github.com/annchain/OG/og/types"
    24  
    25  	"github.com/annchain/OG/protocol"
    26  	"sync/atomic"
    27  	"time"
    28  
    29  	"github.com/annchain/OG/common/crypto"
    30  	"github.com/annchain/OG/ogcore/miner"
    31  	"github.com/sirupsen/logrus"
    32  )
    33  
    34  type TipGenerator interface {
    35  	GetRandomTips(n int) (v []types.Txi)
    36  	GetByNonce(addr common.Address, nonce uint64) types.Txi
    37  	IsBadSeq(seq *types.Sequencer) error
    38  }
    39  
    40  type StateRootProvider interface {
    41  	PreConfirm(seq *types.Sequencer) (hash types2.Hash, err error)
    42  }
    43  
    44  // OGTxCreator creates tx and do the signing and mining for OG.
    45  type OGTxCreator struct {
    46  	Miner              *miner.PoWMiner
    47  	TipGenerator       TipGenerator      // usually tx_pool
    48  	MaxTxHash          types2.Hash       // The difficultiy of TxHash
    49  	MaxMinedHash       types2.Hash       // The difficultiy of MinedHash
    50  	MaxConnectingTries int               // Max number of times to find a pair of parents. If exceeded, try another nonce.
    51  	DebugNodeId        int               // Only for debug. This value indicates tx sender and is temporarily saved to tx.height
    52  	GraphVerifier      protocol.Verifier // To verify the graph structure
    53  	quit               bool
    54  	archiveNonce       uint64
    55  	NoVerifyMineHash   bool
    56  	NoVerifyMaxTxHash  bool
    57  	StateRootProvider  StateRootProvider
    58  }
    59  
    60  func (t *OGTxCreator) GetArchiveNonce() uint64 {
    61  	return atomic.AddUint64(&t.archiveNonce, 1)
    62  }
    63  
    64  func (t *OGTxCreator) Stop() {
    65  	t.quit = true
    66  }
    67  
    68  func (m *OGTxCreator) newUnsignedTx(req UnsignedTxBuildRequest) *types.Tx {
    69  	tx := types.Tx{
    70  		Hash: types2.Hash{},
    71  		//ParentsHash:  nil,
    72  		//MineNonce:    0,
    73  		AccountNonce: req.AccountNonce,
    74  		From:         req.From,
    75  		To:           req.To,
    76  		Value:        req.Value,
    77  		TokenId:      req.TokenId,
    78  		//Data:         nil,
    79  		//PublicKey:    ogcrypto.PublicKey{},
    80  		//Signature:    ogcrypto.Signature{},
    81  		//Height:       0,
    82  		//Weight:       0,
    83  	}
    84  	return &tx
    85  }
    86  
    87  //func (m *OGTxCreator) NewArchiveWithSeal(data []byte) (tx types.Txi, err error) {
    88  //	tx = &archive.Archive{
    89  //		TxBase: types.TxBase{
    90  //			AccountNonce: m.GetArchiveNonce(),
    91  //			Type:         types.TxBaseTypeArchive,
    92  //		},
    93  //		Data: data,
    94  //	}
    95  //
    96  //	if ok := m.SealTx(tx, nil); !ok {
    97  //		logrus.Warn("failed to seal tx")
    98  //		err = fmt.Errorf("failed to seal tx")
    99  //		return
   100  //	}
   101  //	logrus.WithField("tx", tx).Debugf("tx generated")
   102  //
   103  //	return tx, nil
   104  //}
   105  
   106  func (m *OGTxCreator) NewTxWithSeal(req TxWithSealBuildRequest) (tx types.Txi, err error) {
   107  	tx = &types.Tx{
   108  		//Hash:         common.Hash{},
   109  		//ParentsHash:  nil,
   110  		//MineNonce:    0,
   111  		AccountNonce: req.Nonce,
   112  		From:         req.From,
   113  		To:           req.To,
   114  		Value:        req.Value,
   115  		TokenId:      req.TokenId,
   116  		//Data:         nil,
   117  		PublicKey: req.Pubkey,
   118  		Signature: req.Sig,
   119  		//Height:       0,
   120  		//Weight:       0,
   121  	}
   122  
   123  	if ok := m.SealTx(tx, nil); !ok {
   124  		logrus.Warn("failed to seal tx")
   125  		err = fmt.Errorf("failed to seal tx")
   126  		return
   127  	}
   128  	logrus.WithField("tx", tx).Debugf("tx generated")
   129  
   130  	return tx, nil
   131  }
   132  
   133  //func (m *OGTxCreator) NewActionTxWithSeal(req ActionTxBuildRequest) (tx types.Txi, err error) {
   134  //	tx = &types.ActionTx{
   135  //		From: &req.From,
   136  //		// TODO
   137  //		// should consider the case that to is nil. (contract creation)
   138  //		TxBase: types.TxBase{
   139  //			AccountNonce: req.AccountNonce,
   140  //			Type:         types.TxBaseAction,
   141  //		},
   142  //		Action: req.Action,
   143  //		ActionData: &types.InitialOffering{
   144  //			Value:     req.Value,
   145  //			EnableSPO: req.EnableSpo,
   146  //			TokenId:   req.TokenId,
   147  //			TokenName: req.TokenName,
   148  //		},
   149  //	}
   150  //	tx.GetBase().Signature = req.Sig.SignatureBytes
   151  //	tx.GetBase().PublicKey = req.Pubkey.KeyBytes
   152  //
   153  //	if ok := m.SealTx(tx, nil); !ok {
   154  //		err = fmt.Errorf("failed to seal tx")
   155  //		return
   156  //	}
   157  //	logrus.WithField("tx", tx).Debugf("tx generated")
   158  //	tx.SetVerified(types.VerifiedFormat)
   159  //	return tx, nil
   160  //}
   161  
   162  func (m *OGTxCreator) NewSignedTx(req SignedTxBuildRequest) types.Txi {
   163  	if req.PrivateKey.Type != og_interface.Signer.GetCryptoType() {
   164  		panic("ogcrypto type mismatch")
   165  	}
   166  	tx := m.newUnsignedTx(req.UnsignedTxBuildRequest)
   167  	// do sign work
   168  	signature := og_interface.Signer.Sign(req.PrivateKey, tx.SignatureTargets())
   169  	tx.Signature = signature
   170  	tx.PublicKey = og_interface.Signer.PubKey(req.PrivateKey)
   171  	tx.Hash = m.Miner.CalcHash(tx)
   172  	return tx
   173  }
   174  
   175  func (m *OGTxCreator) newUnsignedSequencer(req UnsignedSequencerBuildRequest) *types.Sequencer {
   176  	tx := &types.Sequencer{
   177  		//Hash:         common.Hash{},
   178  		//ParentsHash:  nil,
   179  		Height: req.Height,
   180  		//MineNonce:    0,
   181  		AccountNonce: req.AccountNonce,
   182  		Issuer:       req.Issuer,
   183  		//Signature:    nil,
   184  		//PublicKey:    nil,
   185  		//StateRoot:    common.Hash{},
   186  		//Weight:       0,
   187  	}
   188  	return tx
   189  }
   190  
   191  //NewSignedSequencer this function is for test
   192  func (m *OGTxCreator) NewSignedSequencer(req SignedSequencerBuildRequest) types.Txi {
   193  	if req.PrivateKey.Type != og_interface.Signer.GetCryptoType() {
   194  		panic("ogcrypto type mismatch")
   195  	}
   196  	tx := m.newUnsignedSequencer(req.UnsignedSequencerBuildRequest)
   197  	// do sign work
   198  	logrus.Tracef("seq before sign, the sign type is: %s", og_interface.Signer.GetCryptoType().String())
   199  	signature := og_interface.Signer.Sign(req.PrivateKey, tx.SignatureTargets())
   200  	tx.Signature = signature.SignatureBytes
   201  	tx.PublicKey = og_interface.Signer.PubKey(req.PrivateKey).KeyBytes
   202  	tx.Hash = m.Miner.CalcHash(tx)
   203  	return tx
   204  }
   205  
   206  // validateGraphStructure validates if parents are not conflicted, not double spending or other misbehaviors
   207  func (m *OGTxCreator) validateGraphStructure(parents []types.Txi) (ok bool) {
   208  	ok = true
   209  	for _, parent := range parents {
   210  		ok = ok && m.GraphVerifier.Verify(parent)
   211  		if !ok {
   212  			return
   213  		}
   214  	}
   215  	return
   216  }
   217  
   218  func (m *OGTxCreator) tryConnect(tx types.Txi, parents []types.Txi, privateKey *crypto.PrivateKey) (txRet types.Txi, ok bool) {
   219  	parentHashes := make(types2.Hashes, len(parents))
   220  	for i, parent := range parents {
   221  		parentHashes[i] = parent.GetHash()
   222  	}
   223  	//calculate weight
   224  	tx.SetHeight(tx.CalculateWeight(parents))
   225  	tx.SetParents(parentHashes)
   226  	// verify if the hash of the structure meet the standard.
   227  	hash := m.Miner.CalcHash(tx)
   228  	if m.NoVerifyMaxTxHash || m.Miner.IsHashValid(tx, hash, m.MaxTxHash) {
   229  		tx.SetHash(hash)
   230  		logrus.WithField("hash", hash).WithField("parent", tx.GetParents()).Trace("new tx connected")
   231  		// yes
   232  		txRet = tx
   233  		//ok = m.validateGraphStructure(parents)
   234  		//todo why verify here duplicated verification
   235  		ok = m.GraphVerifier.Verify(tx)
   236  		if !ok {
   237  			logrus.WithField("tx ", tx).Debug("NOT OK")
   238  			return txRet, ok
   239  		}
   240  
   241  		//tx.SetVerified(types.VerifiedGraph)
   242  		//ok = true
   243  		logrus.WithFields(logrus.Fields{
   244  			"tx": tx,
   245  			"ok": ok,
   246  		}).Trace("validate graph structure for tx being connected")
   247  
   248  		if tx.GetType() == types.TxBaseTypeSequencer {
   249  			txs := tx.(*types.Sequencer)
   250  			txs.Signature = og_interface.Signer.Sign(*privateKey, tx.SignatureTargets()).SignatureBytes
   251  			txs.SetHash(m.Miner.CalcHash(tx))
   252  		}
   253  
   254  		return txRet, ok
   255  	} else {
   256  		//logrus.Debugf("Failed to connected %s %s", hash.Hex(), m.MaxTxHash.Hex())
   257  		return nil, false
   258  	}
   259  }
   260  
   261  // SealTx do mining first, then pick up parents from tx pool which could leads to a proper hash.
   262  // If there is no proper parents, Mine again.
   263  func (m *OGTxCreator) SealTx(tx types.Txi, priveKey *crypto.PrivateKey) (ok bool) {
   264  	// record the mining times.
   265  	mineCount := 0
   266  	connectionTries := 0
   267  	minedNonce := uint64(0)
   268  
   269  	timeStart := time.Now()
   270  	respChan := make(chan uint64)
   271  	defer close(respChan)
   272  	done := false
   273  	for !done {
   274  		if m.quit {
   275  			logrus.Info("got quit signal")
   276  			return false
   277  		}
   278  		mineCount++
   279  		if !m.NoVerifyMineHash {
   280  			goroutine.New(func() {
   281  				m.Miner.Mine(tx, m.MaxMinedHash, minedNonce+1, respChan)
   282  				//m.Miner.StartMine(tx, m.MaxMinedHash, minedNonce+1, respChan)
   283  			})
   284  		} else {
   285  			goroutine.New(func() {
   286  				respChan <- 1
   287  			})
   288  		}
   289  		select {
   290  		case minedNonce = <-respChan:
   291  			// Actually, this value is already set during mining.
   292  			// Incase that other implementation does not do that, re-assign
   293  			tx.SetMineNonce(minedNonce)
   294  			//logrus.Debugf("Total time for Mining: %d ns, %d times", time.Since(timeStart).Nanoseconds(), minedNonce)
   295  			// pick up parents.
   296  			for i := 0; i < m.MaxConnectingTries; i++ {
   297  				if m.quit {
   298  					logrus.Info("got quit signal")
   299  					return false
   300  				}
   301  				connectionTries++
   302  				var txs types.Txis
   303  				var ancestor types.Txi
   304  				//if tx.GetType() != types.TxBaseTypeArchive {
   305  				ancestor = m.TipGenerator.GetByNonce(tx.Sender(), tx.GetNonce()-1)
   306  				//}
   307  
   308  				// if there is a previous my tx that is in current seq,
   309  				// use it as my parent.
   310  				// it is required to accelerate validating
   311  				if ancestor != nil && ancestor.Valid() {
   312  					txs = m.TipGenerator.GetRandomTips(2)
   313  					var include bool
   314  					for _, tx := range txs {
   315  						if tx.GetHash() == ancestor.GetHash() {
   316  							include = true
   317  							break
   318  						}
   319  					}
   320  					if !include && len(txs) > 0 {
   321  						txs[0] = ancestor
   322  					}
   323  
   324  				} else {
   325  					txs = m.TipGenerator.GetRandomTips(2)
   326  				}
   327  
   328  				//logrus.Debugf("Got %d Tips: %s", len(txs), common.HashesToString(tx.GetParents()))
   329  				if len(txs) == 0 {
   330  					// Impossible. At least genesis is there
   331  					logrus.Warn("at least genesis is there. Wait for loading")
   332  					time.Sleep(time.Second * 2)
   333  					continue
   334  				}
   335  
   336  				if _, ok := m.tryConnect(tx, txs, priveKey); ok {
   337  					done = true
   338  					break
   339  				} else {
   340  					logrus.WithField("parents ", txs).WithField("connection tries ", connectionTries).WithField("tx ", tx).Debug("NOT OK")
   341  				}
   342  			}
   343  			if mineCount > 1 {
   344  				return false
   345  			}
   346  		case <-time.NewTimer(time.Minute * 5).C:
   347  			//m.Miner.Stop()
   348  			return false
   349  		}
   350  	}
   351  	logrus.WithFields(logrus.Fields{
   352  		"elapsedns":  time.Since(timeStart).Nanoseconds(),
   353  		"re-mine":    mineCount,
   354  		"nonce":      minedNonce,
   355  		"re-connect": connectionTries,
   356  	}).Debugf("total time for mining")
   357  	return true
   358  }
   359  
   360  func (m *OGTxCreator) GenerateSequencer(issuer common.Address, height uint64, accountNonce uint64,
   361  	privateKey *crypto.PrivateKey, blsPubKey []byte) (seq *types.Sequencer, reterr error, genAgain bool) {
   362  
   363  	tx := m.newUnsignedSequencer(UnsignedSequencerBuildRequest{
   364  		Height:       height,
   365  		Issuer:       issuer,
   366  		AccountNonce: accountNonce,
   367  	})
   368  	//for sequencer no mined nonce
   369  	// record the mining times.
   370  	pubkey := og_interface.Signer.PubKey(*privateKey)
   371  	tx.PublicKey = pubkey.KeyBytes
   372  	tx.SetSender(pubkey.Address())
   373  	if blsPubKey != nil {
   374  		// proposed by bft
   375  		tx.PublicKey = blsPubKey
   376  		//tx.BlsJointPubKey = blsPubKey
   377  		//tx.Proposing = true
   378  	}
   379  	// else it is proposed by delegate for solo
   380  	connectionTries := 0
   381  	timeStart := time.Now()
   382  	//logrus.Debugf("Total time for Mining: %d ns, %d times", time.Since(timeStart).Nanoseconds(), minedNonce)
   383  	// pick up parents.
   384  	var ok bool
   385  	for connectionTries = 0; connectionTries < m.MaxConnectingTries; connectionTries++ {
   386  		if m.quit {
   387  			logrus.Info("got quit signal")
   388  			reterr = errors.New("quit")
   389  			return nil, reterr, false
   390  		}
   391  		parents := m.TipGenerator.GetRandomTips(2)
   392  
   393  		//logrus.Debugf("Got %d Tips: %s", len(txs), common.HashesToString(tx.GetParents()))
   394  		if len(parents) == 0 {
   395  			// Impossible. At least genesis is there
   396  			logrus.Warn("at least genesis is there. Wait for loading")
   397  			time.Sleep(time.Second * 1)
   398  			continue
   399  		}
   400  		parentHashes := make(types2.Hashes, len(parents))
   401  		for i, parent := range parents {
   402  			parentHashes[i] = parent.GetHash()
   403  		}
   404  
   405  		//calculate weight
   406  		tx.SetWeight(tx.CalculateWeight(parents))
   407  		tx.SetParents(parentHashes)
   408  		// verify if the hash of the structure meet the standard.
   409  		logrus.WithField("id ", tx.GetHeight()).WithField("parent", tx.GetParents()).Trace("new tx connected")
   410  		//ok = m.validateGraphStructure(parents)
   411  		ok = m.GraphVerifier.Verify(tx)
   412  		if !ok {
   413  			logrus.Debug("NOT OK")
   414  			logrus.WithFields(logrus.Fields{
   415  				"tx": tx,
   416  				"ok": ok,
   417  			}).Trace("validate graph structure for tx being connected")
   418  			if reterr = m.TipGenerator.IsBadSeq(tx); reterr != nil {
   419  				return nil, reterr, true
   420  			}
   421  			continue
   422  		} else {
   423  			//calculate root
   424  			//calculate signatrue
   425  			root, err := m.StateRootProvider.PreConfirm(tx)
   426  			if err != nil {
   427  				logrus.WithField("seq ", tx).Errorf("CalculateStateRoot err  %v", err)
   428  				return nil, err, false
   429  			}
   430  			tx.StateRoot = root
   431  			tx.Signature = og_interface.Signer.Sign(*privateKey, tx.SignatureTargets()).SignatureBytes
   432  			tx.SetHash(m.Miner.CalcHash(tx))
   433  			//tx.SetVerified(types.VerifiedGraph)
   434  			//tx.SetVerified(types.VerifiedFormat)
   435  			break
   436  		}
   437  	}
   438  	if ok {
   439  		logrus.WithFields(logrus.Fields{
   440  			"elapsedns":  time.Since(timeStart).Nanoseconds(),
   441  			"re-connect": connectionTries,
   442  		}).Tracef("total time for mining")
   443  		return tx, nil, false
   444  	}
   445  	logrus.WithFields(logrus.Fields{
   446  		"elapsedns":  time.Since(timeStart).Nanoseconds(),
   447  		"re-connect": connectionTries,
   448  	}).Warnf("generate sequencer failed")
   449  	return nil, nil, false
   450  }
   451  
   452  func (t *OGTxCreator) ValidateSequencer(seq types.Sequencer) error {
   453  	// TODO: validate sequencer's graph structure and txs being confirmed.
   454  	// using Preconfirm in tx_pool
   455  	return nil
   456  }