Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bc135759e8
|
||
|
|
cad695c676
|
||
|
|
1adecdde2d
|
||
|
|
4e7ed45e80
|
||
|
|
576e62507b
|
||
|
|
88870dc12d
|
||
|
|
7d5ceb9a28
|
||
|
|
21db658575
|
||
|
|
909b85b2b7
|
||
|
|
2f9663a8f8
|
||
|
|
637ead1a38
|
||
|
|
412018fc64
|
||
|
|
95663621bc
|
||
|
|
0726f7a730
|
||
|
|
2c8ad85307
|
||
|
|
5df6656981
|
19
CHANGELOG
19
CHANGELOG
@@ -1,3 +1,22 @@
|
|||||||
|
* 0.4.8
|
||||||
|
- Add unlock action description to info loglevel for unlock tool
|
||||||
|
* 0.4.7
|
||||||
|
- Upgrade shep to avoid sync in persist set
|
||||||
|
* 0.4.6
|
||||||
|
- Upgrade shep to handle filesystem list exception
|
||||||
|
* 0.4.5
|
||||||
|
- Upgrade chainlib
|
||||||
|
- Upgrade shep to guarantee atomic state locks
|
||||||
|
* 0.4.4
|
||||||
|
- Reinstate tx index bump in sync state on filter execution complete
|
||||||
|
* 0.4.3
|
||||||
|
- Refactor lock code, move into module from runnable script
|
||||||
|
* 0.4.2
|
||||||
|
- Same as 0.4.1
|
||||||
|
* 0.4.1
|
||||||
|
- Correct runnable entry in setup
|
||||||
|
* 0.4.0
|
||||||
|
- Refactor on shep
|
||||||
* 0.3.7
|
* 0.3.7
|
||||||
- Remove hard eth dependency in settings rendering
|
- Remove hard eth dependency in settings rendering
|
||||||
- Add unlock cli tool
|
- Add unlock cli tool
|
||||||
|
|||||||
1
chainsyncer/__init__.py
Normal file
1
chainsyncer/__init__.py
Normal file
@@ -0,0 +1 @@
|
|||||||
|
from .filter import SyncFilter
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
# standard imports
|
|
||||||
import os
|
|
||||||
|
|
||||||
# local imports
|
|
||||||
from .base import *
|
|
||||||
from .arg import process_flags
|
|
||||||
from .config import process_config
|
|
||||||
|
|
||||||
|
|
||||||
__script_dir = os.path.dirname(os.path.realpath(__file__))
|
|
||||||
data_dir = os.path.join(os.path.dirname(__script_dir), 'data')
|
|
||||||
config_dir = os.path.join(data_dir, 'config')
|
|
||||||
@@ -1,14 +1,14 @@
|
|||||||
# local imports
|
def apply_flag(flag):
|
||||||
from .base import SyncFlag
|
flag.add('range')
|
||||||
|
flag.add('head')
|
||||||
|
flag.alias('sync_range_ext', 'range', 'head')
|
||||||
|
return flag
|
||||||
|
|
||||||
|
|
||||||
def process_flags(argparser, flags):
|
def apply_arg(arg):
|
||||||
|
arg.add_long('offset', 'range', typ=int, help='Block to start sync from. Default is start of history (0).')
|
||||||
if flags & SyncFlag.RANGE > 0:
|
arg.add_long('until', 'range', typ=int, default=-1, help='Block to stop sync on. Default is stop at block height of first run.')
|
||||||
argparser.add_argument('--offset', type=int, help='Block to start sync from. Default is start of history (0).')
|
arg.add_long('single', 'range', typ=bool, help='Execute a single sync, regardless of previous states')
|
||||||
argparser.add_argument('--until', type=int, default=-1, help='Block to stop sync on. Default is stop at block height of first run.')
|
arg.add_long('head', 'head', typ=bool, help='Start from latest block as offset')
|
||||||
if flags & SyncFlag.HEAD > 0:
|
arg.add_long('keep-alive', 'head', typ=bool, help='Do not stop syncing when caught up')
|
||||||
argparser.add_argument('--head', action='store_true', help='Start from latest block as offset')
|
return arg
|
||||||
argparser.add_argument('--keep-alive', action='store_true', help='Do not stop syncing when caught up')
|
|
||||||
|
|
||||||
argparser.add_argument('--backend', type=str, help='Backend to use for state store')
|
|
||||||
|
|||||||
@@ -1,20 +1,18 @@
|
|||||||
# external imports
|
def process_config(config, arg, args, flags):
|
||||||
from chainsyncer.cli import SyncFlag
|
|
||||||
|
|
||||||
|
|
||||||
def process_config(config, args, flags):
|
|
||||||
args_override = {}
|
args_override = {}
|
||||||
|
|
||||||
args_override['SYNCER_BACKEND'] = getattr(args, 'backend')
|
args_override['SYNCER_BACKEND'] = getattr(args, 'backend')
|
||||||
|
|
||||||
if flags & SyncFlag.RANGE:
|
if arg.match('range', flags):
|
||||||
args_override['SYNCER_OFFSET'] = getattr(args, 'offset')
|
args_override['SYNCER_OFFSET'] = getattr(args, 'offset')
|
||||||
args_override['SYNCER_LIMIT'] = getattr(args, 'until')
|
args_override['SYNCER_LIMIT'] = getattr(args, 'until')
|
||||||
|
|
||||||
config.dict_override(args_override, 'local cli args')
|
config.dict_override(args_override, 'local cli args')
|
||||||
|
|
||||||
if flags & SyncFlag.HEAD:
|
if arg.match('head', flags):
|
||||||
config.add(getattr(args, 'keep_alive'), '_KEEP_ALIVE')
|
config.add(getattr(args, 'keep_alive'), '_KEEP_ALIVE')
|
||||||
config.add(getattr(args, 'head'), '_HEAD')
|
config.add(getattr(args, 'head'), '_HEAD')
|
||||||
|
|
||||||
|
config.add(getattr(args, 'single'), '_SINGLE')
|
||||||
|
|
||||||
return config
|
return config
|
||||||
|
|||||||
@@ -97,7 +97,6 @@ class FilterState:
|
|||||||
if self.scan != None:
|
if self.scan != None:
|
||||||
ks = self.scan()
|
ks = self.scan()
|
||||||
for v in ks: #os.listdir(self.scan_path):
|
for v in ks: #os.listdir(self.scan_path):
|
||||||
logg.debug('ks {}'.format(v))
|
|
||||||
k = None
|
k = None
|
||||||
try:
|
try:
|
||||||
k = self.state_store.from_elements(v)
|
k = self.state_store.from_elements(v)
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
|
|
||||||
@@ -41,5 +41,5 @@ class SyncSession:
|
|||||||
if not self.item.release(interrupt=interrupt):
|
if not self.item.release(interrupt=interrupt):
|
||||||
break
|
break
|
||||||
self.item.reset()
|
self.item.reset()
|
||||||
#self.next()
|
self.next()
|
||||||
self.session_store.disconnect()
|
self.session_store.disconnect()
|
||||||
|
|||||||
@@ -11,45 +11,40 @@ from chainlib.settings import ChainSettings
|
|||||||
logg = logging.getLogger(__name__)
|
logg = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class ChainsyncerSettings(ChainSettings):
|
def process_sync_range(settings, config):
|
||||||
|
o = settings.get('SYNCER_INTERFACE').block_latest()
|
||||||
|
r = settings.get('CONN').do(o)
|
||||||
|
block_offset = int(strip_0x(r), 16) + 1
|
||||||
|
logg.info('network block height at startup is {}'.format(block_offset))
|
||||||
|
|
||||||
def process_sync_backend(self, config):
|
keep_alive = False
|
||||||
self.o['SYNCER_BACKEND'] = config.get('SYNCER_BACKEND')
|
session_block_offset = 0
|
||||||
|
block_limit = 0
|
||||||
|
until = 0
|
||||||
|
|
||||||
|
if config.true('_HEAD'):
|
||||||
|
settings.set('SYNCER_OFFSET', block_offset)
|
||||||
|
settings.set('SYNCER_LIMIT', -1)
|
||||||
|
return settings
|
||||||
|
|
||||||
def process_sync_range(self, config):
|
session_block_offset = int(config.get('SYNCER_OFFSET'))
|
||||||
o = self.o['SYNCER_INTERFACE'].block_latest()
|
until = int(config.get('SYNCER_LIMIT'))
|
||||||
r = self.o['RPC'].do(o)
|
|
||||||
block_offset = int(strip_0x(r), 16) + 1
|
|
||||||
logg.info('network block height at startup is {}'.format(block_offset))
|
|
||||||
|
|
||||||
keep_alive = False
|
if until > 0:
|
||||||
session_block_offset = 0
|
if until <= session_block_offset:
|
||||||
block_limit = 0
|
raise ValueError('sync termination block number must be later than offset ({} >= {})'.format(session_block_offset, until))
|
||||||
until = 0
|
block_limit = until
|
||||||
|
elif until == -1:
|
||||||
|
keep_alive = True
|
||||||
|
|
||||||
if config.true('_HEAD'):
|
if session_block_offset == -1:
|
||||||
self.o['SYNCER_OFFSET'] = block_offset
|
session_block_offset = block_offset
|
||||||
self.o['SYNCER_LIMIT'] = -1
|
elif config.true('_KEEP_ALIVE'):
|
||||||
return
|
block_limit = -1
|
||||||
|
else:
|
||||||
|
if block_limit == 0:
|
||||||
|
block_limit = block_offset
|
||||||
|
|
||||||
session_block_offset = int(config.get('SYNCER_OFFSET'))
|
settings.set('SYNCER_OFFSET', session_block_offset)
|
||||||
until = int(config.get('SYNCER_LIMIT'))
|
settings.set('SYNCER_LIMIT', block_limit)
|
||||||
|
return settings
|
||||||
if until > 0:
|
|
||||||
if until <= session_block_offset:
|
|
||||||
raise ValueError('sync termination block number must be later than offset ({} >= {})'.format(session_block_offset, until))
|
|
||||||
block_limit = until
|
|
||||||
elif until == -1:
|
|
||||||
keep_alive = True
|
|
||||||
|
|
||||||
if session_block_offset == -1:
|
|
||||||
session_block_offset = block_offset
|
|
||||||
elif config.true('_KEEP_ALIVE'):
|
|
||||||
block_limit = -1
|
|
||||||
else:
|
|
||||||
if block_limit == 0:
|
|
||||||
block_limit = block_offset
|
|
||||||
|
|
||||||
self.o['SYNCER_OFFSET'] = session_block_offset
|
|
||||||
self.o['SYNCER_LIMIT'] = block_limit
|
|
||||||
|
|||||||
@@ -43,7 +43,6 @@ class SyncItem:
|
|||||||
self.filter_state = filter_state
|
self.filter_state = filter_state
|
||||||
self.state_key = str(offset)
|
self.state_key = str(offset)
|
||||||
|
|
||||||
logg.debug('get key {}'.format(self.state_key))
|
|
||||||
v = self.sync_state.get(self.state_key)
|
v = self.sync_state.get(self.state_key)
|
||||||
|
|
||||||
(self.cursor, self.tx_cursor, self.target) = sync_state_deserialize(v)
|
(self.cursor, self.tx_cursor, self.target) = sync_state_deserialize(v)
|
||||||
@@ -101,10 +100,6 @@ class SyncItem:
|
|||||||
self.sync_state.replace(self.state_key, b)
|
self.sync_state.replace(self.state_key, b)
|
||||||
|
|
||||||
|
|
||||||
def __find_advance(self):
|
|
||||||
v = self.filter_state.state(self.state_key)
|
|
||||||
|
|
||||||
|
|
||||||
def advance(self, ignore_lock=False):
|
def advance(self, ignore_lock=False):
|
||||||
if self.skip_filter:
|
if self.skip_filter:
|
||||||
raise FilterDone()
|
raise FilterDone()
|
||||||
@@ -267,7 +262,9 @@ class SyncStore:
|
|||||||
self.item_keys.append(k)
|
self.item_keys.append(k)
|
||||||
logg.info('added existing {}'.format(o))
|
logg.info('added existing {}'.format(o))
|
||||||
|
|
||||||
self.get_target()
|
v = self.get_target()
|
||||||
|
if v != None:
|
||||||
|
target = v
|
||||||
|
|
||||||
if len(thresholds) == 0:
|
if len(thresholds) == 0:
|
||||||
if self.target != None:
|
if self.target != None:
|
||||||
@@ -332,7 +329,8 @@ class SyncStore:
|
|||||||
if locked_item_key == None:
|
if locked_item_key == None:
|
||||||
return False
|
return False
|
||||||
locked_item = self.get(locked_item_key)
|
locked_item = self.get(locked_item_key)
|
||||||
locked_state = self.filter_state.state(locked_item_key) - self.filter_state.state_store.LOCK
|
state = self.filter_state.state(locked_item_key)
|
||||||
|
locked_state = state - self.filter_state.state_store.LOCK
|
||||||
locked_state_name = self.filter_state.name(locked_state)
|
locked_state_name = self.filter_state.name(locked_state)
|
||||||
|
|
||||||
logg.debug('found locked item {} in state {}'.format(locked_item, locked_state))
|
logg.debug('found locked item {} in state {}'.format(locked_item, locked_state))
|
||||||
@@ -342,10 +340,17 @@ class SyncStore:
|
|||||||
if i == -1:
|
if i == -1:
|
||||||
raise FilterInitializationError('locked state {} ({}) found for item {}, but matching filter has not been registered'.format(locked_state_name, locked_state, locked_item))
|
raise FilterInitializationError('locked state {} ({}) found for item {}, but matching filter has not been registered'.format(locked_state_name, locked_state, locked_item))
|
||||||
|
|
||||||
|
direction = None
|
||||||
if revert:
|
if revert:
|
||||||
self.__unlock_previous(locked_item, fltrs, i)
|
self.__unlock_previous(locked_item, fltrs, i)
|
||||||
|
new_state = self.filter_state.state(locked_item_key)
|
||||||
|
direction = 'previous'
|
||||||
else:
|
else:
|
||||||
self.__unlock_next(locked_item, fltrs, i)
|
self.__unlock_next(locked_item, fltrs, i)
|
||||||
|
new_state = self.filter_state.state(locked_item_key)
|
||||||
|
direction = 'next'
|
||||||
|
|
||||||
|
logg.info('chainstate unlock to {} {} ({}) -> {} ({})'.format(direction, self.filter_state.name(state), state, self.filter_state.name(new_state), new_state))
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ class SyncFsStore(SyncStore):
|
|||||||
create_path = True
|
create_path = True
|
||||||
|
|
||||||
if create_path:
|
if create_path:
|
||||||
self.__create_path(base_path, self.default_path, session_id=session_id)
|
#self.__create_path(base_path, self.default_path, session_id=session_id)
|
||||||
|
os.makedirs(self.session_path)
|
||||||
|
|
||||||
self.session_id = os.path.basename(self.session_path)
|
self.session_id = os.path.basename(self.session_path)
|
||||||
logg.info('session id {} resolved {} path {}'.format(session_id, self.session_id, self.session_path))
|
logg.info('session id {} resolved {} path {}'.format(session_id, self.session_id, self.session_path))
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
confini~=0.6.0
|
confini~=0.6.1
|
||||||
semver==2.13.0
|
semver==2.13.0
|
||||||
hexathon~=0.1.5
|
hexathon~=0.1.7
|
||||||
chainlib~=0.1.1
|
chainlib~=0.3.0
|
||||||
shep~=0.2.3
|
shep~=0.2.9
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[metadata]
|
[metadata]
|
||||||
name = chainsyncer
|
name = chainsyncer
|
||||||
version = 0.4.3
|
version = 0.5.0
|
||||||
description = Generic blockchain syncer driver
|
description = Generic blockchain syncer driver
|
||||||
author = Louis Holbrook
|
author = Louis Holbrook
|
||||||
author_email = dev@holbrook.no
|
author_email = dev@holbrook.no
|
||||||
@@ -30,6 +30,7 @@ packages =
|
|||||||
chainsyncer.store
|
chainsyncer.store
|
||||||
chainsyncer.cli
|
chainsyncer.cli
|
||||||
chainsyncer.runnable
|
chainsyncer.runnable
|
||||||
|
chainsyncer.data
|
||||||
|
|
||||||
#[options.package_data]
|
#[options.package_data]
|
||||||
#* =
|
#* =
|
||||||
|
|||||||
Reference in New Issue
Block a user