github.com/aquanetwork/aquachain@v1.7.8/cmd/aquastrat/main.go (about)

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