Full Code of etherchain-org/ethpool-core for AI

master 8038b967e365 cached
3 files
14.3 KB
3.9k tokens
21 symbols
1 requests
Download .txt
Repository: etherchain-org/ethpool-core
Branch: master
Commit: 8038b967e365
Files: 3
Total size: 14.3 KB

Directory structure:
gitextract_88qhdlsa/

├── LICENSE
├── README.md
└── pool.go

================================================
FILE CONTENTS
================================================

================================================
FILE: LICENSE
================================================
The MIT License (MIT)

Copyright (c) 2015 etherchain-org

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.



================================================
FILE: README.md
================================================
# Introduction
We have decided to open source our implementation of pooled mining for Ethereum. This software is not a complete mining pool. It only takes care of work distribution and share validation; valid shares are stored into a local database (LevelDB). Reward calculation and payments are not yet implemented but it should be possible to connect this software some of the  existing open source mining pools.

# Performance
While the current implementation in go might not be the most effective one, the pool was able to process ~600 workers at 30% CPU utilization (1 core) and 70MB RAM usage.

# Supported clients
The pool has been tested successfully with both the go Ethereum client (geth) and the cpp Ethereum client (eth).

# Pull requests & possible optimizations
If you find any issues with the pool software please feel free to issue a pull request.

If you want to improve the pool, implementing the connection to geth via IPC instead of HTTP would be a good start.

# Setup guide (Ubuntu 14.04)
* Install go according to https://github.com/ethereum/go-ethereum/wiki/Installing-Go#ubuntu-1404
* Put the pool.go file into your gopath
* Run go get to download the dependencies
* Adjust the ports to match your environment (poolPort and ethereumPort)
* Start your Ethereum client & enable RPC
* Run go build pool.go
* Start the pool server ./pool
* Point your miner to http://ip:port/miner/\<account\>.\<worker\>/\<hashrate\>

# Donations
Donations are always welcome:

BTC: 37rfj6oPJmnEDHTnUxvsUEmF4CnqofgWJr

ETH: 0xc5d2dd8b399b67d857ed6d91bbe26f0702f7cd34


================================================
FILE: pool.go
================================================
package main

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"math/big"
	"net/http"
	"os"
	"strconv"
	"strings"
	"time"

	"github.com/ethereum/ethash"
	"github.com/ethereum/go-ethereum/common"

	"github.com/gorilla/mux"

	"github.com/syndtr/goleveldb/leveldb"
)

var levelDB *leveldb.DB

var currWork *ResponseArray = nil

var pendingBlockNumber uint64 = 0
var pendingBlockDifficulty *big.Int

var invalidRequest = `{
  "id":64,
  "jsonrpc": "2.0",
  "result": false,
  "error": "invalid request"
}`

var okRequest = `{
  "id":64,
  "jsonrpc": "2.0",
  "result": true
}`

var pow256 = common.BigPow(2, 256)

var hasher = ethash.New()

var poolPort = "5082"
var ethereumPort = "8545" //8545 = geth, 8080 = eth (requires dev branch when using eth client)

var logInfo *log.Logger
var logError *log.Logger

type ResponseArray struct {
	Id      int           `json:"id"`
	Jsonrpc string        `json:"jsonrpc"`
	Result  []interface{} `json:"result"`
}

type ResponseJSON struct {
	Id      int                    `json:"id"`
	Jsonrpc string                 `json:"jsonrpc"`
	Result  map[string]interface{} `json:"result"`
}

type ResponseBool struct {
	Id      int    `json:"id"`
	Jsonrpc string `json:"jsonrpc"`
	Result  bool   `json:"result"`
}

type Request struct {
	Id      int           `json:"id"`
	Jsonrpc string        `json:"jsonrpc"`
	Method  string        `json:"method"`
	Params  []interface{} `json:"params"`
}

type block struct {
	difficulty  *big.Int
	hashNoNonce common.Hash
	nonce       uint64
	mixDigest   common.Hash
	number      uint64
}

func (b block) Difficulty() *big.Int     { return b.difficulty }
func (b block) HashNoNonce() common.Hash { return b.hashNoNonce }
func (b block) Nonce() uint64            { return b.nonce }
func (b block) MixDigest() common.Hash   { return b.mixDigest }
func (b block) NumberU64() uint64        { return b.number }

func main() {
	// Set up logging
	logInfo = log.New(os.Stderr, "INFO: ", log.Ldate|log.Ltime)
	logError = log.New(os.Stderr, "ERROR: ", log.Ldate|log.Ltime)
	logInfo.Println("Welcome to ethpool 2.0")
	logInfo.Println("Pool port is", poolPort)
	logInfo.Println("Point your miners to: http://<ip>:" + poolPort + "/miner/{miner}/{difficulty}")

	// Open the share database
	var err error

	levelDB, err = leveldb.OpenFile("~/ethpool_shares.db", nil)
	if err != nil {
		logError.Println("Unable to open leveldb connection:", err)
		return
	}
	defer levelDB.Close()

	go updateWork()
	go updatePendingBlock()
	go submitShares()
	// names := []interface{}{"pending", false}

	// pb := callJSON("eth_getBlockByNumber", names)
	// fmt.Println(pb.Result["number"])

	// fmt.Scanln()
	r := mux.NewRouter()
	r.HandleFunc("/miner/{miner}/{difficulty}", handleMiner)
	http.Handle("/", r)
	log.Fatal(http.ListenAndServe(":5082", nil))
}

func handleMiner(rw http.ResponseWriter, req *http.Request) {

	vars := mux.Vars(req)

	minerDifficulty, err := strconv.ParseFloat(vars["difficulty"], 64)
	if err != nil {
		logError.Println("Invalid difficulty provided: " + vars["difficulty"])
		minerDifficulty = 5 // Set a fixed difficulty (5MH/s) in this case
		// fmt.Fprint(rw, getErrorResponse("Invalid difficulty provided: "+vars["difficulty"]))
		// return
	}
	minerAdjustedDifficulty := int64(minerDifficulty * 1000000 * 100)

	minerArray := strings.Split(vars["miner"], ".")

	if len(minerArray) == 0 || len(minerArray) > 2 {
		logError.Println("Invalid miner & worker provided: " + vars["miner"])
		fmt.Fprint(rw, getErrorResponse("Invalid miner & worker provided: "+vars["miner"]))
		return
	}

	miner := strings.Replace(minerArray[0], "0x", "", -1)
	worker := "default"

	if len(minerArray) == 2 {
		worker = minerArray[1]
	}

	if len(miner) != 40 {
		logError.Println("Invalid ethereum address provided: 0x" + miner)
		fmt.Fprint(rw, getErrorResponse("Invalid ethereum address provided: 0x"+miner))
		return
	}

	decoder := json.NewDecoder(req.Body)
	var t Request
	err = decoder.Decode(&t)
	if err != nil {
		logError.Println("Invalid JSON request: ", err)
		fmt.Fprint(rw, getErrorResponse("Invalid JSON request"))
		return
	}

	if t.Method == "eth_getWork" {
		difficulty := big.NewInt(minerAdjustedDifficulty)
		// Send the response
		fmt.Fprint(rw, getWorkPackage(difficulty))
	} else if t.Method == "eth_submitHashrate" {
		fmt.Fprint(rw, okRequest)
	} else if t.Method == "eth_submitWork" {
		paramsOrig := t.Params[:]

		hashNoNonce := t.Params[1].(string)
		nonce, err := strconv.ParseUint(strings.Replace(t.Params[0].(string), "0x", "", -1), 16, 64)
		if err != nil {
			logError.Println("Invalid nonce provided: ", err)
			fmt.Fprint(rw, getErrorResponse("Invalid nonce provided"))
			return
		}

		mixDigest := t.Params[2].(string)

		myBlock := block{
			number:      pendingBlockNumber,
			hashNoNonce: common.HexToHash(hashNoNonce),
			difficulty:  big.NewInt(minerAdjustedDifficulty),
			nonce:       nonce,
			mixDigest:   common.HexToHash(mixDigest),
		}

		myBlockRealDiff := block{
			number:      pendingBlockNumber,
			hashNoNonce: common.HexToHash(hashNoNonce),
			difficulty:  pendingBlockDifficulty,
			nonce:       nonce,
			mixDigest:   common.HexToHash(mixDigest),
		}

		if hasher.Verify(myBlock) {
			//fmt.Println("Share is valid")
			if hasher.Verify(myBlockRealDiff) {
				submitWork(paramsOrig)
				logInfo.Println("###########################################################################")
				logInfo.Println("################################Block found################################")
				logInfo.Println("###########################################################################")
			}

			share := `MIX:` + mixDigest + `|MINER:"` + miner + `|DIFFICULTY:` + strconv.FormatInt(minerAdjustedDifficulty, 10) + `|WORKER:` + worker
			logInfo.Println("Miner", miner, ".", worker, "found valid share (Diff:", minerAdjustedDifficulty, "Mix:", mixDigest, "Hash:", hashNoNonce, "Nonce:", nonce, ")")
			err = levelDB.Put([]byte(mixDigest), []byte(share), nil)

			if err != nil {
				logError.Println("Error inserting share into database:", err)
			}
		} else {
			logError.Println("Miner", miner, "provided invalid share")
			fmt.Fprint(rw, getErrorResponse("Provided PoW solution is invalid!"))
		}
		fmt.Fprint(rw, okRequest)
	} else {
		logError.Println("Method " + t.Method + " not implemented!")
		fmt.Fprint(rw, getErrorResponse("Method "+t.Method+" not implemented!"))
	}
}

func getWorkPackage(difficulty *big.Int) string {

	if currWork == nil {
		return getErrorResponse("Current work unavailable")
	}

	// Our response object
	response := &ResponseArray{
		Id:      currWork.Id,
		Jsonrpc: currWork.Jsonrpc,
		Result:  currWork.Result[:],
	}

	// Calculte requested difficulty
	diff := new(big.Int).Div(pow256, difficulty)
	diffBytes := string(common.ToHex(diff.Bytes()))

	// Adjust the difficulty for the miner
	response.Result[2] = diffBytes

	// Convert respone object to JSON
	b, _ := json.Marshal(response)

	return string(b)

}

func updateWork() {
	for true {
		currWorkNew, err := callArray("eth_getWork", []interface{}{})

		if err == nil {
			currWork = currWorkNew
		} else {
			currWork = nil
		}

		// fmt.Println("Current work", currWork.Result[0])
		time.Sleep(time.Millisecond * 100)
	}
}

func submitWork(params []interface{}) {
	result, err := callBool("eth_submitWork", params)
	if err == nil {
		logInfo.Println(result.Result)
	}
}

func submitShares() {
	for true {
		iter := levelDB.NewIterator(nil, nil)
		for iter.Next() {
			key := iter.Key()
			value := iter.Value()
			_ = value
			logInfo.Println("Do smth with the share (e.g. send to pool database):", string(key))
		}
		iter.Release()
		err := iter.Error()
		if err != nil {
			logError.Println("Error itarating shares:", err)
		}
		time.Sleep(time.Second * 10)
	}
}

func updatePendingBlock() {
	params := []interface{}{"pending", false}

	for true {
		block, err := callJSON("eth_getBlockByNumber", params)
		if err == nil {
			blockNbr, err := strconv.ParseUint(strings.Replace(block.Result["number"].(string), "0x", "", -1), 16, 64)
			if err == nil {
				pendingBlockNumber = blockNbr
			}

			blockDiff, err := strconv.ParseInt(strings.Replace(block.Result["difficulty"].(string), "0x", "", -1), 16, 64)
			if err == nil {
				pendingBlockDifficulty = big.NewInt(blockDiff)
				// logInfo.Println("Pending block difficulty:", pendingBlockDifficulty)
			}
		}
		time.Sleep(time.Millisecond * 100)
	}
}

func callArray(method string, params []interface{}) (*ResponseArray, error) {
	url := "http://localhost:" + ethereumPort
	jsonReq := &Request{
		Id:      1,
		Jsonrpc: "2.0",
		Method:  method,
		Params:  params,
	}
	reqJSON, _ := json.Marshal(jsonReq)
	// fmt.Println(string(reqJSON))
	req, err := http.NewRequest("POST", url, bytes.NewBuffer(reqJSON))

	if err != nil {
		logError.Println("Could not create POST request", err)
		return nil, errors.New("Could not create POST request")
	}

	req.Header.Set("Content-Type", "application/json")

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		logError.Println("Could not send POST request to Ethereum client", err)
		return nil, errors.New("Could not send POST request to Ethereum client")
	}

	defer resp.Body.Close()
	body, _ := ioutil.ReadAll(resp.Body)

	// fmt.Println(string(body))
	res := &ResponseArray{}

	if err := json.Unmarshal(body, res); err != nil {
		logError.Println("Ethereum client returned unexpected data", err)
		return nil, errors.New("Ethereum client returned unexpected data")
	}

	// fmt.Println("done")
	return res, nil
}

func callBool(method string, params []interface{}) (*ResponseBool, error) {
	url := "http://localhost:" + ethereumPort
	jsonReq := &Request{
		Id:      1,
		Jsonrpc: "2.0",
		Method:  method,
		Params:  params,
	}
	reqJSON, _ := json.Marshal(jsonReq)
	// fmt.Println(string(reqJSON))
	req, err := http.NewRequest("POST", url, bytes.NewBuffer(reqJSON))

	if err != nil {
		logError.Println("Could not create POST request", err)
		return nil, errors.New("Could not create POST request")
	}

	req.Header.Set("Content-Type", "application/json")

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		logError.Println("Could not send POST request to Ethereum client", err)
		return nil, errors.New("Could not send POST request to Ethereum client")
	}

	defer resp.Body.Close()
	body, _ := ioutil.ReadAll(resp.Body)

	// fmt.Println(string(body))
	res := &ResponseBool{}

	if err := json.Unmarshal(body, res); err != nil {
		logError.Println("Ethereum client returned unexpected data", err)
		return nil, errors.New("Ethereum client returned unexpected data")
	}

	// fmt.Println("done")
	return res, nil
}

func callJSON(method string, params []interface{}) (*ResponseJSON, error) {
	url := "http://localhost:" + ethereumPort
	jsonReq := &Request{
		Id:      1,
		Jsonrpc: "2.0",
		Method:  method,
		Params:  params,
	}
	reqJSON, _ := json.Marshal(jsonReq)
	// fmt.Println(string(reqJSON))
	req, err := http.NewRequest("POST", url, bytes.NewBuffer(reqJSON))

	if err != nil {
		logError.Println("Could not create POST request", err)
		return nil, errors.New("Could not create POST request")
	}

	req.Header.Set("Content-Type", "application/json")

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		logError.Println("Could not send POST request to Ethereum client", err)
		return nil, errors.New("Could not send POST request to Ethereum client")
	}

	defer resp.Body.Close()
	body, _ := ioutil.ReadAll(resp.Body)

	// fmt.Println(string(body))
	res := &ResponseJSON{}

	if err := json.Unmarshal(body, res); err != nil {
		logError.Println("Ethereum client returned unexpected data", err)
		return nil, errors.New("Ethereum client returned unexpected data")
	}

	// fmt.Println("done")
	return res, nil
}

func getErrorResponse(errorMsg string) string {
	return `{
    "id":64,
    "jsonrpc": "2.0",
    "result": false,
    "error": "` + errorMsg + `"
  }`
}
Download .txt
gitextract_88qhdlsa/

├── LICENSE
├── README.md
└── pool.go
Download .txt
SYMBOL INDEX (21 symbols across 1 files)

FILE: pool.go
  type ResponseArray (line 55) | type ResponseArray struct
  type ResponseJSON (line 61) | type ResponseJSON struct
  type ResponseBool (line 67) | type ResponseBool struct
  type Request (line 73) | type Request struct
  type block (line 80) | type block struct
    method Difficulty (line 88) | func (b block) Difficulty() *big.Int     { return b.difficulty }
    method HashNoNonce (line 89) | func (b block) HashNoNonce() common.Hash { return b.hashNoNonce }
    method Nonce (line 90) | func (b block) Nonce() uint64            { return b.nonce }
    method MixDigest (line 91) | func (b block) MixDigest() common.Hash   { return b.mixDigest }
    method NumberU64 (line 92) | func (b block) NumberU64() uint64        { return b.number }
  function main (line 94) | func main() {
  function handleMiner (line 127) | func handleMiner(rw http.ResponseWriter, req *http.Request) {
  function getWorkPackage (line 232) | func getWorkPackage(difficulty *big.Int) string {
  function updateWork (line 259) | func updateWork() {
  function submitWork (line 274) | func submitWork(params []interface{}) {
  function submitShares (line 281) | func submitShares() {
  function updatePendingBlock (line 299) | func updatePendingBlock() {
  function callArray (line 320) | func callArray(method string, params []interface{}) (*ResponseArray, err...
  function callBool (line 361) | func callBool(method string, params []interface{}) (*ResponseBool, error) {
  function callJSON (line 402) | func callJSON(method string, params []interface{}) (*ResponseJSON, error) {
  function getErrorResponse (line 443) | func getErrorResponse(errorMsg string) string {
Condensed preview — 3 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (16K chars).
[
  {
    "path": "LICENSE",
    "chars": 1082,
    "preview": "The MIT License (MIT)\n\nCopyright (c) 2015 etherchain-org\n\nPermission is hereby granted, free of charge, to any person ob"
  },
  {
    "path": "README.md",
    "chars": 1571,
    "preview": "# Introduction\nWe have decided to open source our implementation of pooled mining for Ethereum. This software is not a c"
  },
  {
    "path": "pool.go",
    "chars": 11948,
    "preview": "package main\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io/ioutil\"\n\t\"log\"\n\t\"math/big\"\n\t\"net/http\"\n\t\"os\"\n\t\"st"
  }
]

About this extraction

This page contains the full source code of the etherchain-org/ethpool-core GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 3 files (14.3 KB), approximately 3.9k tokens, and a symbol index with 21 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!