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 }