first commit
This commit is contained in:
@@ -0,0 +1,64 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import pdb
|
||||
from pprint import pprint
|
||||
import re
|
||||
import sys
|
||||
import os
|
||||
sys.path.append(os.path.normpath(os.path.join(os.path.dirname(__file__), '../lib')))
|
||||
import config
|
||||
from models import Superblock, Proposal, GovernanceObject, Setting, Signal, Vote, Outcome
|
||||
from models import VoteSignals, VoteOutcomes
|
||||
from peewee import PeeweeException # , OperationalError, IntegrityError
|
||||
#from dashd import DashDaemon
|
||||
from sibcoind import SibcoinDaemon
|
||||
import dashlib
|
||||
from decimal import Decimal
|
||||
#dashd = DashDaemon.from_dash_conf(config.dash_conf)
|
||||
sibcoind = SibcoinDaemon.from_sibcoin_conf(config.sibcoin_conf)
|
||||
import misc
|
||||
# ==============================================================================
|
||||
# do stuff here
|
||||
|
||||
pr = Proposal(
|
||||
name='proposal7',
|
||||
url='https://dashcentral.com/proposal7',
|
||||
payment_address='yTC62huR4YQEPn9AJHjnQxxreHSbgAoatV',
|
||||
payment_amount=39.23,
|
||||
start_epoch=1483250400,
|
||||
end_epoch=1491022800,
|
||||
)
|
||||
|
||||
# sb = Superblock(
|
||||
# event_block_height = 62500,
|
||||
# payment_addresses = "yYe8KwyaUu5YswSYmB3q3ryx8XTUu9y7Ui|yTC62huR4YQEPn9AJHjnQxxreHSbgAoatV",
|
||||
# payment_amounts = "5|3"
|
||||
# )
|
||||
|
||||
|
||||
# TODO: make this a test, mock 'dashd' and tie a test block height to a
|
||||
# timestamp, ensure only unit testing a within_window method
|
||||
#
|
||||
# also, create the `within_window` or similar method & use that.
|
||||
#
|
||||
bh = 131112
|
||||
bh_epoch = sibcoind.block_height_to_epoch(bh)
|
||||
|
||||
fudge = 72000
|
||||
window_start = 1483689082 - fudge
|
||||
window_end = 1483753726 + fudge
|
||||
|
||||
print("Window start: %s" % misc.epoch2str(window_start))
|
||||
print("Window end: %s" % misc.epoch2str(window_end))
|
||||
print("\nbh_epoch: %s" % misc.epoch2str(bh_epoch))
|
||||
|
||||
|
||||
if (bh_epoch < window_start or bh_epoch > window_end):
|
||||
print("outside of window!")
|
||||
else:
|
||||
print("Within window, we're good!")
|
||||
|
||||
# pdb.set_trace()
|
||||
# dashd.get_object_list()
|
||||
# ==============================================================================
|
||||
# pdb.set_trace()
|
||||
1
|
||||
@@ -0,0 +1,10 @@
|
||||
import binascii
|
||||
import sys
|
||||
|
||||
usage = "%s <hex>" % sys.argv[0]
|
||||
|
||||
if len(sys.argv) < 2:
|
||||
print(usage)
|
||||
else:
|
||||
json = binascii.unhexlify(sys.argv[1])
|
||||
print(json)
|
||||
@@ -0,0 +1,21 @@
|
||||
import simplejson
|
||||
import binascii
|
||||
import sys
|
||||
import pdb
|
||||
from pprint import pprint
|
||||
import sys
|
||||
import os
|
||||
sys.path.append(os.path.normpath(os.path.join(os.path.dirname(__file__), '../lib')))
|
||||
import dashlib
|
||||
# ============================================================================
|
||||
usage = "%s <hex>" % sys.argv[0]
|
||||
|
||||
obj = None
|
||||
if len(sys.argv) < 2:
|
||||
print(usage)
|
||||
sys.exit(1)
|
||||
else:
|
||||
obj = dashlib.deserialise(sys.argv[1])
|
||||
|
||||
pdb.set_trace()
|
||||
1
|
||||
+211
@@ -0,0 +1,211 @@
|
||||
#!/usr/bin/env python
|
||||
import sys
|
||||
import os
|
||||
sys.path.append(os.path.normpath(os.path.join(os.path.dirname(__file__), '../lib')))
|
||||
import init
|
||||
import config
|
||||
import misc
|
||||
#from dashd import DashDaemon
|
||||
from sibcoind import SibcoinDaemon
|
||||
from models import Superblock, Proposal, GovernanceObject
|
||||
from models import VoteSignals, VoteOutcomes, Transient
|
||||
import socket
|
||||
from misc import printdbg
|
||||
import time
|
||||
from bitcoinrpc.authproxy import JSONRPCException
|
||||
import signal
|
||||
import atexit
|
||||
import random
|
||||
from scheduler import Scheduler
|
||||
import argparse
|
||||
|
||||
|
||||
# sync dashd gobject list with our local relational DB backend
|
||||
def perform_dashd_object_sync(dashd):
|
||||
GovernanceObject.sync(dashd)
|
||||
|
||||
|
||||
def prune_expired_proposals(dashd):
|
||||
# vote delete for old proposals
|
||||
for proposal in Proposal.expired(dashd.superblockcycle()):
|
||||
proposal.vote(dashd, VoteSignals.delete, VoteOutcomes.yes)
|
||||
|
||||
|
||||
# ping dashd
|
||||
def sentinel_ping(dashd):
|
||||
printdbg("in sentinel_ping")
|
||||
|
||||
dashd.ping()
|
||||
|
||||
printdbg("leaving sentinel_ping")
|
||||
|
||||
|
||||
def attempt_superblock_creation(dashd):
|
||||
import dashlib
|
||||
|
||||
if not dashd.is_masternode():
|
||||
print("We are not a Masternode... can't submit superblocks!")
|
||||
return
|
||||
|
||||
# query votes for this specific ebh... if we have voted for this specific
|
||||
# ebh, then it's voted on. since we track votes this is all done using joins
|
||||
# against the votes table
|
||||
#
|
||||
# has this masternode voted on *any* superblocks at the given event_block_height?
|
||||
# have we voted FUNDING=YES for a superblock for this specific event_block_height?
|
||||
|
||||
event_block_height = dashd.next_superblock_height()
|
||||
|
||||
if Superblock.is_voted_funding(event_block_height):
|
||||
# printdbg("ALREADY VOTED! 'til next time!")
|
||||
|
||||
# vote down any new SBs because we've already chosen a winner
|
||||
for sb in Superblock.at_height(event_block_height):
|
||||
if not sb.voted_on(signal=VoteSignals.funding):
|
||||
sb.vote(dashd, VoteSignals.funding, VoteOutcomes.no)
|
||||
|
||||
# now return, we're done
|
||||
return
|
||||
|
||||
if not dashd.is_govobj_maturity_phase():
|
||||
printdbg("Not in maturity phase yet -- will not attempt Superblock")
|
||||
return
|
||||
|
||||
proposals = Proposal.approved_and_ranked(proposal_quorum=dashd.governance_quorum(), next_superblock_max_budget=dashd.next_superblock_max_budget())
|
||||
budget_max = dashd.get_superblock_budget_allocation(event_block_height)
|
||||
sb_epoch_time = dashd.block_height_to_epoch(event_block_height)
|
||||
|
||||
sb = dashlib.create_superblock(proposals, event_block_height, budget_max, sb_epoch_time)
|
||||
if not sb:
|
||||
printdbg("No superblock created, sorry. Returning.")
|
||||
return
|
||||
|
||||
# find the deterministic SB w/highest object_hash in the DB
|
||||
dbrec = Superblock.find_highest_deterministic(sb.hex_hash())
|
||||
if dbrec:
|
||||
dbrec.vote(dashd, VoteSignals.funding, VoteOutcomes.yes)
|
||||
|
||||
# any other blocks which match the sb_hash are duplicates, delete them
|
||||
for sb in Superblock.select().where(Superblock.sb_hash == sb.hex_hash()):
|
||||
if not sb.voted_on(signal=VoteSignals.funding):
|
||||
sb.vote(dashd, VoteSignals.delete, VoteOutcomes.yes)
|
||||
|
||||
printdbg("VOTED FUNDING FOR SB! We're done here 'til next superblock cycle.")
|
||||
return
|
||||
else:
|
||||
printdbg("The correct superblock wasn't found on the network...")
|
||||
|
||||
# if we are the elected masternode...
|
||||
if (dashd.we_are_the_winner()):
|
||||
printdbg("we are the winner! Submit SB to network")
|
||||
sb.submit(dashd)
|
||||
|
||||
|
||||
def check_object_validity(dashd):
|
||||
# vote (in)valid objects
|
||||
for gov_class in [Proposal, Superblock]:
|
||||
for obj in gov_class.select():
|
||||
obj.vote_validity(dashd)
|
||||
|
||||
|
||||
def is_dashd_port_open(dashd):
|
||||
# test socket open before beginning, display instructive message to MN
|
||||
# operators if it's not
|
||||
port_open = False
|
||||
try:
|
||||
info = dashd.rpc_command('getgovernanceinfo')
|
||||
port_open = True
|
||||
except (socket.error, JSONRPCException) as e:
|
||||
print("%s" % e)
|
||||
|
||||
return port_open
|
||||
|
||||
|
||||
def main():
|
||||
dashd = SibcoinDaemon.from_sibcoin_conf(config.sibcoin_conf)
|
||||
|
||||
# check dashd connectivity
|
||||
if not is_dashd_port_open(dashd):
|
||||
print("Cannot connect to sibcoind. Please ensure sibcoind is running and the JSONRPC port is open to Sentinel.")
|
||||
return
|
||||
|
||||
# check dashd sync
|
||||
if not dashd.is_synced():
|
||||
print("sibcoind not synced with network! Awaiting full sync before running Sentinel.")
|
||||
return
|
||||
|
||||
# ensure valid masternode
|
||||
if not dashd.is_masternode():
|
||||
print("Invalid Masternode Status, cannot continue.")
|
||||
return
|
||||
|
||||
|
||||
if init.options.bypass:
|
||||
# bypassing scheduler, remove the scheduled event
|
||||
printdbg("--bypass-schedule option used, clearing schedule")
|
||||
Scheduler.clear_schedule()
|
||||
|
||||
if not Scheduler.is_run_time():
|
||||
printdbg("Not yet time for an object sync/vote, moving on.")
|
||||
return
|
||||
|
||||
if not init.options.bypass:
|
||||
# delay to account for cron minute sync
|
||||
Scheduler.delay()
|
||||
|
||||
# running now, so remove the scheduled event
|
||||
Scheduler.clear_schedule()
|
||||
|
||||
# ========================================================================
|
||||
# general flow:
|
||||
# ========================================================================
|
||||
#
|
||||
# load "gobject list" rpc command data, sync objects into internal database
|
||||
perform_dashd_object_sync(dashd)
|
||||
|
||||
if dashd.has_sentinel_ping:
|
||||
sentinel_ping(dashd)
|
||||
|
||||
# auto vote network objects as valid/invalid
|
||||
# check_object_validity(dashd)
|
||||
|
||||
# vote to delete expired proposals
|
||||
prune_expired_proposals(dashd)
|
||||
|
||||
# create a Superblock if necessary
|
||||
attempt_superblock_creation(dashd)
|
||||
|
||||
# schedule the next run
|
||||
Scheduler.schedule_next_run()
|
||||
|
||||
|
||||
def signal_handler(signum, frame):
|
||||
print("Got a signal [%d], cleaning up..." % (signum))
|
||||
Transient.delete('SENTINEL_RUNNING')
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def cleanup():
|
||||
Transient.delete(mutex_key)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
atexit.register(cleanup)
|
||||
signal.signal(signal.SIGINT, signal_handler)
|
||||
|
||||
# ensure another instance of Sentinel is not currently running
|
||||
mutex_key = 'SENTINEL_RUNNING'
|
||||
# assume that all processes expire after 'timeout_seconds' seconds
|
||||
timeout_seconds = 90
|
||||
|
||||
is_running = Transient.get(mutex_key)
|
||||
if is_running:
|
||||
printdbg("An instance of Sentinel is already running -- aborting.")
|
||||
sys.exit(1)
|
||||
else:
|
||||
Transient.set(mutex_key, misc.now(), timeout_seconds)
|
||||
|
||||
# locked to this instance -- perform main logic here
|
||||
main()
|
||||
|
||||
Transient.delete(mutex_key)
|
||||
Reference in New Issue
Block a user