gitlab.com/aquachain/aquachain@v1.17.16-rc3.0.20221018032414-e3ddf1e1c055/cmd/aquastrat/main.go (about)

     1  // Copyright 2018 The aquachain Authors
     2  // This file is part of aquachain.
     3  //
     4  // aquachain is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // aquachain is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU General Public License
    15  // along with aquachain. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package main
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  	"math/big"
    23  	"math/rand"
    24  	"os"
    25  	"path/filepath"
    26  	"strings"
    27  	"time"
    28  
    29  	cli "github.com/urfave/cli"
    30  	"gitlab.com/aquachain/aquachain/cmd/utils"
    31  	"gitlab.com/aquachain/aquachain/common"
    32  	"gitlab.com/aquachain/aquachain/consensus/aquahash"
    33  	"gitlab.com/aquachain/aquachain/consensus/lightvalid"
    34  	"gitlab.com/aquachain/aquachain/core/types"
    35  	"gitlab.com/aquachain/aquachain/internal/debug"
    36  	"gitlab.com/aquachain/aquachain/opt/aquaclient"
    37  	"gitlab.com/aquachain/aquachain/params"
    38  	"gitlab.com/aquachain/aquachain/rlp"
    39  	rpc "gitlab.com/aquachain/aquachain/rpc/rpcclient"
    40  )
    41  
    42  var gitCommit = ""
    43  
    44  var (
    45  	app    = utils.NewApp(gitCommit, "usage")
    46  	big1   = big.NewInt(1)
    47  	Config *params.ChainConfig
    48  )
    49  
    50  func init() {
    51  	app.Name = "aquastrat"
    52  	app.Action = loopit
    53  	_ = filepath.Join
    54  	app.Flags = append(debug.Flags, []cli.Flag{
    55  		cli.StringFlag{
    56  			//Value: filepath.Join(utils.DataDirFlag.Value.String(), "testnet/aquachain.ipc"),
    57  			Value: "https://tx.aquacha.in/testnet/",
    58  			Name:  "rpc",
    59  			Usage: "path or url to rpc",
    60  		},
    61  		cli.StringFlag{
    62  			Value: "",
    63  			Name:  "coinbase",
    64  			Usage: "address for mining rewards",
    65  		},
    66  	}...)
    67  }
    68  
    69  //valid block #1 using -testnet2
    70  var header1 = &types.Header{
    71  	Difficulty: big.NewInt(4096),
    72  	Extra:      []byte{0xd4, 0x83, 0x01, 0x07, 0x04, 0x89, 0x61, 0x71, 0x75, 0x61, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x85, 0x6c, 0x69, 0x6e, 0x75, 0x78},
    73  	GasLimit:   4704588,
    74  	GasUsed:    0,
    75  	// Hash: "0x73851a4d607acd8341cf415beeed9c8b8c803e1e835cb45080f6af7a2127e807",
    76  	Coinbase:    common.HexToAddress("0xcf8e5ba37426404bef34c3ca4fa2d2ed9be41e58"),
    77  	MixDigest:   common.Hash{},
    78  	Nonce:       types.BlockNonce{0x70, 0xc2, 0xdd, 0x45, 0xa3, 0x10, 0x17, 0x35},
    79  	Number:      big.NewInt(1),
    80  	ParentHash:  common.HexToHash("0xde434983d3ada19cd43c44d8ad5511bad01ed12b3cc9a99b1717449a245120df"),
    81  	ReceiptHash: common.HexToHash("0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"),
    82  	UncleHash:   common.HexToHash("0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"),
    83  	Root:        common.HexToHash("0x194b1927f77b77161b58fed1184990d8f7b345fabf8ef8706ee865a844f73bc3"),
    84  	Time:        big.NewInt(1536181711),
    85  	TxHash:      common.HexToHash("0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"),
    86  	Version:     2,
    87  }
    88  
    89  func main() {
    90  	if err := app.Run(os.Args); err != nil {
    91  		fmt.Println("fatal:", err)
    92  	}
    93  }
    94  
    95  func loopit(ctx *cli.Context) error {
    96  	for {
    97  		if err := runit(ctx); err != nil {
    98  			fmt.Println(err)
    99  			return err
   100  		}
   101  	}
   102  }
   103  func runit(ctx *cli.Context) error {
   104  	coinbase := ctx.String("coinbase")
   105  	if coinbase == "" || !strings.HasPrefix(coinbase, "0x") || len(coinbase) != 42 {
   106  		return fmt.Errorf("cant mine with no -coinbase flag, or invalid: len: %v, coinbase: %q", len(coinbase), coinbase)
   107  	}
   108  	coinbaseAddr := common.HexToAddress(coinbase)
   109  
   110  	rpcclient, err := getclient(ctx)
   111  	if err != nil {
   112  		return err
   113  	}
   114  	aqua := aquaclient.NewClient(rpcclient)
   115  	block1, err := aqua.BlockByNumber(context.Background(), big1)
   116  	if err != nil {
   117  		fmt.Println("blockbynumber")
   118  		return err
   119  	}
   120  
   121  	// to get genesis hash, we can't grab block zero and Hash()
   122  	// because we dont know the chainconfig which tells us
   123  	// the version to use for hashing.
   124  	genesisHash := block1.ParentHash()
   125  	switch genesisHash {
   126  	case params.MainnetGenesisHash:
   127  		Config = params.MainnetChainConfig
   128  	case params.TestnetGenesisHash:
   129  		Config = params.TestnetChainConfig
   130  	default:
   131  		Config = params.Testnet2ChainConfig
   132  	}
   133  	parent, err := aqua.BlockByNumber(context.Background(), nil)
   134  	if err != nil {
   135  		fmt.Println("blockbynumber")
   136  		return err
   137  	}
   138  	var encoded []byte
   139  	// first block is on the house (testnet2 only)
   140  	if Config == params.Testnet2ChainConfig && parent.Number().Uint64() == 0 {
   141  		parent.SetVersion(Config.GetBlockVersion(parent.Number()))
   142  		block1 := types.NewBlock(header1, nil, nil, nil)
   143  		encoded, err = rlp.EncodeToBytes(&block1)
   144  		if err != nil {
   145  			return err
   146  		}
   147  	}
   148  	encoded, err = aqua.GetBlockTemplate(context.Background(), coinbaseAddr)
   149  	if err != nil {
   150  		println("gbt")
   151  		return err
   152  	}
   153  	var bt = new(types.Block)
   154  	if err := rlp.DecodeBytes(encoded, bt); err != nil {
   155  		println("getblocktemplate rlp decode error", err.Error())
   156  		return err
   157  	}
   158  
   159  	// modify block
   160  	bt.SetVersion(Config.GetBlockVersion(bt.Number()))
   161  	fmt.Println("mining:")
   162  	fmt.Println(bt)
   163  	encoded, err = mine(Config, parent.Header(), bt)
   164  	if err != nil {
   165  		return err
   166  	}
   167  	if encoded == nil {
   168  		return fmt.Errorf("failed to encoded block to rlp")
   169  	}
   170  	if !aqua.SubmitBlock(context.Background(), encoded) {
   171  		fmt.Println("failed")
   172  		return fmt.Errorf("failed")
   173  	} else {
   174  		fmt.Println("success")
   175  	}
   176  	return nil
   177  
   178  }
   179  
   180  func mine(cfg *params.ChainConfig, parent *types.Header, block *types.Block) ([]byte, error) {
   181  	validator := lightvalid.New()
   182  	rand.Seed(time.Now().UnixNano())
   183  	nonce := uint64(0)
   184  	nonce = rand.Uint64()
   185  	hdr := block.Header()
   186  	fmt.Println("mining algo:", hdr.Version)
   187  	fmt.Printf("#%v, by %x\ndiff: %s\ntx: %s\n", hdr.Number, hdr.Coinbase, hdr.Difficulty, block.Transactions())
   188  	fmt.Printf("starting from nonce: %v\n", nonce)
   189  	second := time.Tick(10 * time.Second)
   190  	fps := uint64(0)
   191  	for {
   192  		select {
   193  		case <-second:
   194  			// not necessary, but impossible with getwork()
   195  			hdr.Time = big.NewInt(time.Now().Unix())
   196  			hdr.Difficulty = aquahash.CalcDifficulty(cfg, hdr.Time.Uint64(), parent, nil)
   197  			fmt.Printf("%s %v h/s\n", hdr.Time, fps/uint64(10))
   198  			fps = 0
   199  		default:
   200  			nonce++
   201  			fps++
   202  			hdr.Nonce = types.EncodeNonce(nonce)
   203  			block = block.WithSeal(hdr)
   204  			block = types.NewBlock(hdr, block.Transactions(), block.Uncles(), []*types.Receipt{})
   205  			if err := validator.VerifyWithError(block); err != nil {
   206  				if err != lightvalid.ErrPOW {
   207  					fmt.Println("error:", err)
   208  				}
   209  				continue
   210  			}
   211  			println("found nonce, encoding block", block.String())
   212  			b, err := rlp.EncodeToBytes(&block)
   213  			if err != nil {
   214  				return nil, err
   215  			}
   216  			fmt.Println(b)
   217  			return b, nil
   218  		}
   219  	}
   220  }
   221  
   222  func getclient(ctx *cli.Context) (*rpc.Client, error) {
   223  	if strings.HasPrefix(ctx.String("rpc"), "http") {
   224  		return rpc.DialHTTP(ctx.String("rpc"))
   225  	} else {
   226  		return rpc.DialIPC(context.Background(), ctx.String("rpc"))
   227  	}
   228  }