Skip to content

Commit 523edbb

Browse files
author
root
committed
improved safe low
1 parent 62ac697 commit 523edbb

File tree

3 files changed

+97
-22
lines changed

3 files changed

+97
-22
lines changed

ethgasstation.py

100644100755
+71-21
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from sqlalchemy.orm import sessionmaker
1212
from sqlalchemy.ext.declarative import declarative_base
1313
from egs_ref import *
14+
import modelparams
1415

1516
web3 = Web3(HTTPProvider('http://localhost:8545'))
1617
engine = create_engine(
@@ -56,7 +57,7 @@ def write_to_sql(alltx, analyzed_block, block_sumdf, mined_blockdf_seen, block):
5657
block_sumdf.to_sql(con=engine, name='blockdata2', if_exists='append', index=False)
5758

5859

59-
def write_to_json(gprecs, txpool_by_gp, prediction_table, analyzed_block):
60+
def write_to_json(gprecs, txpool_by_gp, prediction_table, analyzed_block,submitted_hourago=None):
6061
"""write json data"""
6162
try:
6263
txpool_by_gp = txpool_by_gp.rename(columns={'gas_price':'count'})
@@ -85,6 +86,12 @@ def write_to_json(gprecs, txpool_by_gp, prediction_table, analyzed_block):
8586

8687
with open(filepath_analyzedblock, 'w') as outfile:
8788
outfile.write(analyzed_blockout)
89+
90+
if not submitted_hourago.empty:
91+
submitted_hourago = submitted_hourago.to_json(orient='records')
92+
filepath_hourago = parentdir + '/json/hourago.json'
93+
with open(filepath_hourago, 'w') as outfile:
94+
outfile.write(submitted_hourago)
8895

8996
except Exception as e:
9097
print(e)
@@ -149,13 +156,9 @@ def get_tx_atabove(gasprice, txpool_by_gp):
149156
def predict(row):
150157
if row['chained'] == 1:
151158
return np.nan
152-
intercept = 3.3381
153-
hpa_coef = -0.0172
154-
txatabove_coef= 0.001
155-
interact_coef = 0
156-
high_gas_coef = 1.6907
159+
157160
try:
158-
sum1 = (intercept + (row['hashpower_accepting']*hpa_coef) + (row['tx_atabove']*txatabove_coef) + (row['hgXhpa']*interact_coef) + (row['highgas2']*high_gas_coef))
161+
sum1 = (modelparams.INTERCEPT + (row['hashpower_accepting'] * modelparams.HPA_COEF) + (row['tx_atabove'] * modelparams.TXATABOVE_COEF) + (row['hgXhpa'] * modelparams.INTERACT_COEF) + (row['highgas2'] * modelparams.HIGHGAS_COEF))
159162
prediction = np.exp(sum1)
160163
if prediction < 2:
161164
prediction = 2
@@ -166,6 +169,14 @@ def predict(row):
166169
print(e)
167170
return np.nan
168171

172+
def check_nonce(row, txpool_block_nonce):
173+
if row['num_from']>1:
174+
if row['nonce'] > txpool_block_nonce.loc[row['from_address'],'nonce']:
175+
return 1
176+
if row['nonce'] == txpool_block_nonce.loc[row['from_address'], 'nonce']:
177+
return 0
178+
else:
179+
return 0
169180

170181
def analyze_last200blocks(block, blockdata):
171182
recent_blocks = blockdata.loc[blockdata['block_number'] > (block-200), ['mingasprice', 'block_number', 'gaslimit', 'time_mined', 'speed']]
@@ -206,10 +217,14 @@ def analyze_txpool(block, txpool, alltx, hashpower, avg_timemined, gaslimit):
206217
txpool_block['num_to'] = txpool_block.groupby('to_address')['block_posted'].transform('count')
207218
txpool_block['ico'] = (txpool_block['num_to'] > 90).astype(int)
208219
txpool_block['dump'] = (txpool_block['num_from'] > 5).astype(int)
209-
#group by gasprice
220+
221+
#new dfs grouped by gasprice and nonce
210222
txpool_by_gp = txpool_block[['gas_price', 'round_gp_10gwei']].groupby('round_gp_10gwei').agg({'gas_price':'count'})
211223
txpool_block_nonce = txpool_block[['from_address', 'nonce']].groupby('from_address').agg({'nonce':'min'})
212224

225+
#when multiple tx from same from address, finds tx with lowest nonce (unchained) - others are 'chained'
226+
txpool_block['chained'] = txpool_block.apply(check_nonce, args=(txpool_block_nonce,), axis=1)
227+
213228
#predictiontable
214229
predictTable = pd.DataFrame({'gasprice' : range(10, 1010, 10)})
215230
ptable2 = pd.DataFrame({'gasprice' : range(0, 10, 1)})
@@ -233,8 +248,8 @@ def analyze_txpool(block, txpool, alltx, hashpower, avg_timemined, gaslimit):
233248
#finally, analyze txpool transactions
234249
print('txpool block length ' + str(len(txpool_block)))
235250
txpool_block['pct_limit'] = txpool_block['gas_offered'].apply(lambda x: x / gaslimit)
236-
txpool_block['high_gas_offered'] = (txpool_block['pct_limit']> .037).astype(int)
237-
txpool_block['highgas2'] = (txpool_block['pct_limit'] > .15).astype(int)
251+
txpool_block['high_gas_offered'] = (txpool_block['pct_limit'] > modelparams.HIGHGAS1).astype(int)
252+
txpool_block['highgas2'] = (txpool_block['pct_limit'] > modelparams.HIGHGAS2).astype(int)
238253
txpool_block['hashpower_accepting'] = txpool_block['round_gp_10gwei'].apply(lambda x: gp_lookup[x] if x in gp_lookup else 100)
239254
txpool_block['hgXhpa'] = txpool_block['highgas2']*txpool_block['hashpower_accepting']
240255
txpool_block['tx_atabove'] = txpool_block['round_gp_10gwei'].apply(lambda x: txatabove_lookup[x] if x in txatabove_lookup else 1)
@@ -244,17 +259,40 @@ def analyze_txpool(block, txpool, alltx, hashpower, avg_timemined, gaslimit):
244259
txpool_by_gp.reset_index(inplace=True, drop=False)
245260
return(txpool_block, txpool_by_gp, predictTable)
246261

247-
def get_gasprice_recs(prediction_table, block_time, block, speed, minlow=-1):
262+
def get_gasprice_recs(prediction_table, block_time, block, speed, minlow=-1, submitted_hourago=None):
248263

249-
def get_safelow(minlow):
250-
series = prediction_table.loc[prediction_table['expectedTime'] <= 10, 'gasprice']
251-
safelow = series.min()
264+
def get_safelow(minlow, submitted_hourago):
265+
series = prediction_table.loc[prediction_table['expectedTime'] <= 20, 'gasprice']
266+
model_safelow = series.min()
252267
minhash_list = prediction_table.loc[prediction_table['hashpower_accepting']>=1.5, 'gasprice']
253-
if (safelow < minhash_list.min()):
254-
safelow = minhash_list.min()
268+
if (model_safelow < minhash_list.min()):
269+
model_safelow = minhash_list.min()
255270
if minlow >= 0:
256-
if safelow < minlow:
257-
safelow = minlow
271+
if model_safelow < minlow:
272+
model_safelow = minlow
273+
print('modelled safelow ' + str(model_safelow))
274+
if not submitted_hourago.empty:
275+
series = submitted_hourago.loc[(submitted_hourago['total']>=5) & (submitted_hourago['pct_unmined']>=.1) & (submitted_hourago['still_here']>=2)]
276+
if not series.empty:
277+
unsafe = series.index.max()
278+
else:
279+
unsafe = 0
280+
print('unsafe = ' + str(unsafe))
281+
series1 = submitted_hourago.loc[(submitted_hourago['total']>=3) & ((submitted_hourago['pct_unmined']<.1) | (submitted_hourago['still_here'] <=1 ))]
282+
observed_safelow = series1.loc[series1.index > unsafe]
283+
if not observed_safelow.empty:
284+
observed_safelow = observed_safelow.index.min()
285+
else:
286+
observed_safelow = unsafe + 10
287+
print('observed safelow = ' + str(observed_safelow))
288+
else:
289+
observed_safelow = 0
290+
291+
if unsafe > model_safelow :
292+
safelow = observed_safelow
293+
else:
294+
safelow = model_safelow
295+
print('safelow ' + str(safelow))
258296
return float(safelow)
259297

260298
def get_average():
@@ -293,7 +331,7 @@ def get_wait(gasprice):
293331
return float(wait)
294332

295333
gprecs = {}
296-
gprecs['safeLow'] = get_safelow(minlow)
334+
gprecs['safeLow'] = get_safelow(minlow, submitted_hourago)
297335
gprecs['safeLowWait'] = get_wait(gprecs['safeLow'])
298336
gprecs['average'] = get_average()
299337
gprecs['avgWait'] = get_wait(gprecs['average'])
@@ -367,16 +405,28 @@ def update_dataframes(block):
367405
assert analyzed_block.index.duplicated().sum()==0
368406
alltx = alltx.combine_first(analyzed_block)
369407

408+
submitted_hourago = alltx.loc[(alltx['block_posted'] < (block-250)) & (alltx['block_posted'] > (block-350)) & (alltx['chained']==0) & (alltx['gas_offered'] < 500000)].copy()
409+
print(len(submitted_hourago))
410+
411+
if len(submitted_hourago > 50):
412+
submitted_hourago['still_here'] = submitted_hourago.index.isin(current_txpool.index)
413+
submitted_hourago = submitted_hourago[['gas_price', 'round_gp_10gwei', 'still_here']].groupby('round_gp_10gwei').agg({'gas_price':'count', 'still_here':'sum'})
414+
submitted_hourago.rename(columns={'gas_price':'total'}, inplace=True)
415+
submitted_hourago['pct_unmined'] = submitted_hourago['still_here']/submitted_hourago['total']
416+
370417
#with pd.option_context('display.max_columns', None,):
371418
#print(analyzed_block)
372419
# update tx dataframe with txpool variables and time preidctions
373420

374421
#get gpRecs
375-
gprecs = get_gasprice_recs (predictiondf, block_time, block, speed, timer.minlow)
422+
gprecs = get_gasprice_recs (predictiondf, block_time, block, speed, timer.minlow, submitted_hourago)
376423

377424
#every block, write gprecs, predictions, txpool by gasprice
378425
analyzed_block.reset_index(drop=False, inplace=True)
379-
write_to_json(gprecs, txpool_by_gp, predictiondf, analyzed_block)
426+
if not submitted_hourago.empty:
427+
submitted_hourago.reset_index(drop=False, inplace=True)
428+
submitted_hourago = submitted_hourago.sort_values('round_gp_10gwei')
429+
write_to_json(gprecs, txpool_by_gp, predictiondf, analyzed_block, submitted_hourago)
380430
write_to_sql(alltx, analyzed_block, block_sumdf, mined_blockdf_seen, block)
381431

382432
#keep from getting too large

model_gas.py

100644100755
+1-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
predictData.loc[predictData['chained']==1, 'confirmTime']=np.nan
3535
print('num with confirm times')
3636
print (predictData['confirmTime'].count())
37-
predictData = predictData.dropna(subset=['confirmTime', 'tx_unchained'])
37+
predictData = predictData.dropna(subset=['confirmTime'])
3838
print('post-chained ' + str(len(predictData)))
3939
predictData = predictData.loc[predictData['confirmTime']>0]
4040
print (len(predictData))

modelparams.py

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
'''
2+
this file is for the constants used in the prediction model
3+
these are generated from a geth node with globalslots set to 8000.
4+
If you run locally, you should check to see if these are accurate using model_gas.py
5+
you should also refit the model periodically as they may change over time.
6+
You should have about >20k transactions in the database to fit the model accurately
7+
'''
8+
#intercept from poisson model
9+
#hashpower accepting coefficient
10+
#transactions at or above in txpool coefficient
11+
#interaction term with highgas offered and hashpower. not currently using
12+
#highgas offefred coefficient
13+
14+
INTERCEPT = 4.1401
15+
HPA_COEF = -0.0399
16+
TXATABOVE_COEF = 0.0002
17+
INTERACT_COEF = 0
18+
HIGHGAS_COEF = 1.9645
19+
20+
#high gas offered is defined based as a percentage of the gas limit
21+
#highgas2 is the only one that matters right now
22+
23+
HIGHGAS1 = .037
24+
HIGHGAS2 = .15
25+

0 commit comments

Comments
 (0)