├── requirements.txt ├── .gitignore ├── miner.py ├── requirements.txt.lock ├── README.md └── libethereumcpuminer.py /requirements.txt: -------------------------------------------------------------------------------- 1 | ethereum 2 | web3 3 | 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.idea 2 | *.pyc 3 | .env 4 | 5 | -------------------------------------------------------------------------------- /miner.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import libethereumcpuminer 3 | 4 | root_parser = argparse.ArgumentParser() 5 | root_parser.add_argument('ETHEREUM_URL') 6 | root_parser.add_argument('-n', '--num-blocks', type=int, default=1) 7 | 8 | args = root_parser.parse_args() 9 | 10 | miner = libethereumcpuminer.EthereumCpuMiner(args.ETHEREUM_URL) 11 | miner.mine_n_blocks(args.num_blocks) 12 | -------------------------------------------------------------------------------- /requirements.txt.lock: -------------------------------------------------------------------------------- 1 | certifi==2018.1.18 2 | chardet==3.0.4 3 | cytoolz==0.9.0 4 | eth-abi==0.5.0 5 | eth-keyfile==0.4.1 6 | eth-keys==0.1.0b4 7 | eth-tester==0.1.0b15 8 | eth-utils==0.7.4 9 | ethereum==2.3.0 10 | future==0.16.0 11 | idna==2.6 12 | pbkdf2==1.3 13 | py-ecc==1.4.2 14 | pycryptodome==3.4.8 15 | pyethash==0.1.27 16 | pylru==1.0.9 17 | pysha3==1.0.2 18 | PyYAML==3.12 19 | repoze.lru==0.7 20 | requests==2.18.4 21 | rlp==0.6.0 22 | scrypt==0.8.0 23 | semantic-version==2.6.0 24 | toolz==0.9.0 25 | typing==3.6.4 26 | urllib3==1.22 27 | web3==3.16.4 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Ethereum CPU Miner 2 | 3 | Ondrej Sika 4 | https://github.com/ondrejsika/ethereum-cpu-miner.git 5 | 6 | Python implementation of Ethereum miner for __testing__ on __zero difficulty__ chains. This is __not__ a real miner. 7 | 8 | ## Install 9 | 10 | ``` 11 | git clone git@github.com:ondrejsika/ethereum-cpu-miner.git 12 | cd ethereum-cpu-miner 13 | virtualenv .env 14 | .env/bin/pip install -r requirements.txt.lock 15 | ``` 16 | 17 | ## Run 18 | 19 | Mine 10 blocks 20 | 21 | ``` 22 | .env/bin/python miner.py http://127.0.0.1:8545 -n 10 23 | ``` 24 | 25 | ## Help 26 | 27 | ``` 28 | .env/bin/python miner.py --help 29 | ``` 30 | 31 | -------------------------------------------------------------------------------- /libethereumcpuminer.py: -------------------------------------------------------------------------------- 1 | import binascii 2 | from web3 import Web3, HTTPProvider 3 | from ethereum.pow.ethpow import get_cache, hashimoto_light, TT64M1 4 | from ethereum import utils 5 | 6 | 7 | def hex_to_bin(data_hex): 8 | return binascii.unhexlify(data_hex[2:]) 9 | 10 | 11 | def bin_to_hex(data_bin): 12 | return '0x' + binascii.hexlify(data_bin) 13 | 14 | 15 | class EthereumCpuMiner(object): 16 | def __init__(self, ethereum_url): 17 | self._conn = Web3(HTTPProvider(ethereum_url)) 18 | 19 | self._mining_hash_hex = None 20 | self._mining_hash_bin = None 21 | self._target_bin = None 22 | self._block_number_int = None 23 | self._nonce_bin = None 24 | self._mix_digest_bin = None 25 | 26 | def get_work(self): 27 | self._mining_hash_hex, _, target_hex, block_number_hex = self._conn.eth.getWork() 28 | self._mining_hash_bin, self._target_bin, self._block_number_int = \ 29 | hex_to_bin(self._mining_hash_hex), hex_to_bin(target_hex), int(block_number_hex, 16) 30 | 31 | def mine(self, start_nonce=0): 32 | cache = get_cache(self._block_number_int) 33 | nonce = start_nonce 34 | i = 0 35 | while True: 36 | i += 1 37 | bin_nonce = utils.zpad(utils.int_to_big_endian((nonce + i) & TT64M1), 8) 38 | o = hashimoto_light(self._block_number_int, cache, self._mining_hash_bin, bin_nonce) 39 | if o[b'result'] <= self._target_bin: 40 | assert len(bin_nonce) == 8 41 | assert len(o[b'mix digest']) == 32 42 | 43 | self._nonce_bin = bin_nonce 44 | self._mix_digest_bin = o[b'mix digest'] 45 | return 46 | 47 | def submit_work(self): 48 | nonce_hex, mix_digest_hex = bin_to_hex(self._nonce_bin), bin_to_hex(self._mix_digest_bin) 49 | self._conn.manager.request_blocking("eth_submitWork", [nonce_hex, self._mining_hash_hex, mix_digest_hex]) 50 | 51 | def mine_n_blocks(self, n=1): 52 | for _ in range(n): 53 | self.get_work() 54 | self.mine() 55 | self.submit_work() 56 | 57 | --------------------------------------------------------------------------------