mirror of
https://github.com/status-im/open-bounty.git
synced 2025-01-13 19:15:03 +00:00
Add check-tx-receipts thread; allow only one tx submission at a time
This commit is contained in:
parent
183a50dc94
commit
03cf011f01
@ -145,7 +145,8 @@ RETURNING repo_id, issue_id, issue_number, title, commit_sha, contract_address;
|
||||
-- :name update-transaction-hash :! :n
|
||||
-- :doc updates transaction-hash for a given issue
|
||||
UPDATE issues
|
||||
SET transaction_hash = :transaction_hash
|
||||
SET transaction_hash = :transaction_hash,
|
||||
updated = timezone('utc'::text, now())
|
||||
WHERE issue_id = :issue_id;
|
||||
|
||||
|
||||
@ -241,6 +242,48 @@ WHERE pr_id = :pr_id;
|
||||
-- Bounties ------------------------------------------------------------------------
|
||||
|
||||
|
||||
-- :name unmined-tx-hashes :? :*
|
||||
-- :doc hashes that haven't been mined for some time
|
||||
SELECT
|
||||
CASE WHEN transaction_hash is not null and contract_address is null
|
||||
THEN transaction_hash
|
||||
WHEN execute_hash is not null and confirm_hash is null
|
||||
THEN execute_hash
|
||||
WHEN watch_hash is not null
|
||||
THEN watch_hash
|
||||
END
|
||||
AS tx_hash,
|
||||
CASE WHEN transaction_hash is not null and contract_address is null
|
||||
THEN 'deploy'
|
||||
WHEN execute_hash is not null and confirm_hash is null
|
||||
THEN 'execute'
|
||||
WHEN watch_hash is not null
|
||||
THEN 'watch'
|
||||
END
|
||||
AS type,
|
||||
issue_id
|
||||
FROM issues
|
||||
WHERE updated < timezone('utc'::text, now()) - interval '5 minutes'
|
||||
AND (transaction_hash is not null and contract_address is null
|
||||
OR execute_hash is not null and confirm_hash is null
|
||||
OR watch_hash is not null);
|
||||
|
||||
|
||||
-- :name reset-tx-hash! :! :n
|
||||
-- :doc reset tx hash if it hasn't been mined for some time
|
||||
UPDATE issues
|
||||
SET
|
||||
--~ (when (= (:type params) "deploy") "transaction_hash")
|
||||
--~ (when (= (:type params) "execute") "execute_hash")
|
||||
--~ (when (= (:type params) "watch") "watch_hash")
|
||||
= null
|
||||
WHERE
|
||||
--~ (when (= (:type params) "deploy") "transaction_hash")
|
||||
--~ (when (= (:type params) "execute") "execute_hash")
|
||||
--~ (when (= (:type params) "watch") "watch_hash")
|
||||
= :tx-hash
|
||||
|
||||
|
||||
-- :name pending-contracts :? :*
|
||||
-- :doc bounty issues where deploy contract has failed
|
||||
SELECT
|
||||
@ -254,7 +297,7 @@ FROM issues i, users u, repositories r
|
||||
WHERE
|
||||
r.user_id = u.id
|
||||
AND i.repo_id = r.repo_id
|
||||
AND (i.transaction_hash IS NULL OR updated > now() - interval '1 hour')
|
||||
AND i.transaction_hash IS NULL
|
||||
AND i.contract_address IS NULL;
|
||||
|
||||
|
||||
|
@ -100,3 +100,12 @@
|
||||
[]
|
||||
(jdbc/with-db-connection [con-db *db*]
|
||||
(db/bounties-activity con-db)))
|
||||
|
||||
(defn unmined-tx-hashes []
|
||||
(jdbc/with-db-connection [con-db *db*]
|
||||
(db/unmined-tx-hashes con-db)))
|
||||
|
||||
(defn reset-tx-hash!
|
||||
[tx-hash type]
|
||||
(jdbc/with-db-connection [con-db *db*]
|
||||
(db/reset-tx-hash! con-db {:tx-hash tx-hash :type type})))
|
||||
|
@ -7,6 +7,7 @@
|
||||
[taoensso.tufte :as tufte :refer (defnp p profiled profile)]
|
||||
[clojure.tools.logging :as log]
|
||||
[clojure.string :as str]
|
||||
[clj-time.core :as t]
|
||||
[mount.core :as mount]
|
||||
[pandect.core :as pandect]
|
||||
[commiteth.util.util :refer [json-api-request]])
|
||||
@ -51,26 +52,20 @@
|
||||
(throw (ex-info "Make sure you provided proper credentials in appropriate resources/config.edn"
|
||||
{:password password :file-path file-path}))))))
|
||||
|
||||
|
||||
(def highest-nonce (atom nil))
|
||||
(def nonces-dropped (atom (clojure.lang.PersistentQueue/EMPTY)))
|
||||
|
||||
(defrecord TxNonce [tx-hash nonce type timestamp])
|
||||
(def nonce-being-mined (atom nil))
|
||||
|
||||
(defn get-nonce []
|
||||
(if (seq @nonces-dropped)
|
||||
(let [nonce (peek @nonces-dropped)]
|
||||
(swap! nonces-dropped pop)
|
||||
nonce)
|
||||
(let [nonce (.. (.ethGetTransactionCount @web3j-obj
|
||||
(env :eth-account)
|
||||
DefaultBlockParameterName/LATEST)
|
||||
DefaultBlockParameterName/PENDING)
|
||||
sendAsync
|
||||
get
|
||||
getTransactionCount)]
|
||||
(if (or (nil? @highest-nonce)
|
||||
(> nonce @highest-nonce))
|
||||
(reset! highest-nonce nonce)
|
||||
(swap! highest-nonce (comp biginteger inc))))))
|
||||
(if (or (nil? @nonce-being-mined)
|
||||
(> nonce (:nonce @nonce-being-mined)))
|
||||
(:nonce (reset! nonce-being-mined (TxNonce. nil nonce nil nil)))
|
||||
(throw (Exception. (str "Attempting to re-use old nonce" nonce))))))
|
||||
|
||||
(defn get-signed-tx [gas-price gas-limit to data nonce]
|
||||
"Create a sign a raw transaction.
|
||||
@ -248,8 +243,13 @@
|
||||
|
||||
(defn get-transaction-receipt
|
||||
[hash]
|
||||
(eth-rpc {:method "eth_getTransactionReceipt"
|
||||
:params [hash]}))
|
||||
(when-let [receipt (eth-rpc {:method "eth_getTransactionReceipt"
|
||||
:params [hash]})]
|
||||
(if (= hash (:tx-hash @nonce-being-mined))
|
||||
(reset! nonce-being-mined nil)
|
||||
;; This can happen in case of payout receipts
|
||||
(log/infof "Obtained receipt for tx not currently being mined: " hash))
|
||||
receipt))
|
||||
|
||||
(defn format-call-params
|
||||
[method-id & params]
|
||||
@ -263,7 +263,7 @@
|
||||
:params [{:to contract :data data} "latest"]})))
|
||||
|
||||
(defn execute
|
||||
[{:keys [from contract method-id gas-limit params internal-tx-id]}]
|
||||
[{:keys [from contract method-id gas-limit params internal-tx-id type]}]
|
||||
{:pre [(string? method-id)]}
|
||||
(let [data (apply format-call-params method-id params)
|
||||
gas-price (gas-price)
|
||||
@ -288,12 +288,16 @@
|
||||
(assoc params :gas gas))]
|
||||
(if (offline-signing?)
|
||||
(try
|
||||
(eth-rpc
|
||||
{:method "eth_sendRawTransaction"
|
||||
:params [params]
|
||||
:internal-tx-id internal-tx-id})
|
||||
(let [tx-hash (eth-rpc
|
||||
{:method "eth_sendRawTransaction"
|
||||
:params [params]
|
||||
:internal-tx-id internal-tx-id})]
|
||||
(:tx-hash (swap! nonce-being-mined
|
||||
assoc :tx-hash tx-hash
|
||||
:type type
|
||||
:timestamp (t/now))))
|
||||
(catch Throwable ex
|
||||
(swap! nonces-dropped conj nonce)
|
||||
(reset! nonce-being-mined nil)
|
||||
(throw ex)))
|
||||
(eth-rpc
|
||||
{:method "personal_sendTransaction"
|
||||
|
@ -43,6 +43,7 @@
|
||||
[{:keys [owner internal-tx-id]}]
|
||||
{:pre [(string? owner) (string? internal-tx-id)]}
|
||||
(eth/execute {:internal-tx-id internal-tx-id
|
||||
:type "deploy"
|
||||
:from (eth/eth-account)
|
||||
:contract (factory-contract-addr)
|
||||
:method-id (:create method-ids)
|
||||
@ -93,6 +94,7 @@
|
||||
(:withdraw-everything method-ids)
|
||||
payout-address)]
|
||||
(eth/execute {:internal-tx-id internal-tx-id
|
||||
:type "execute"
|
||||
:from (eth/eth-account)
|
||||
:contract contract
|
||||
:method-id (:submit-transaction method-ids)
|
||||
@ -111,6 +113,7 @@
|
||||
(let [token-address (get-token-address token)]
|
||||
(assert token-address)
|
||||
(eth/execute {:internal-tx-id (str "watch-token-" (System/currentTimeMillis) "-" bounty-addr)
|
||||
:type "watch"
|
||||
:from (eth/eth-account)
|
||||
:contract bounty-addr
|
||||
:method-id (:watch method-ids)
|
||||
|
@ -89,6 +89,7 @@
|
||||
(p :deploy-pending-contracts
|
||||
(doseq [{issue-id :issue_id
|
||||
issue-number :issue_number
|
||||
transaction-hash :transaction_hash
|
||||
owner :owner
|
||||
owner-address :owner_address
|
||||
repo :repo} (db-bounties/pending-contracts)]
|
||||
@ -371,6 +372,25 @@
|
||||
(log/error ex "issue %s: update-balances exception" issue-id)))))
|
||||
(log/info "Exit update-balances"))
|
||||
|
||||
(defn check-tx-receipts
|
||||
"At all times, there should be no more than one unmined tx hash,
|
||||
as we are executing txs sequentially"
|
||||
[]
|
||||
(log/info "In check-tx-receipts")
|
||||
(doseq [{tx-hash :tx_hash
|
||||
type :type
|
||||
issue-id :issue_id} (db-bounties/unmined-tx-hashes)]
|
||||
(log/infof "issue %s: resetting tx operation: %s for hash: %s" issue-id type tx-hash)
|
||||
(db-bounties/reset-tx-hash! tx-hash type)
|
||||
(when (= tx-hash (:tx-hash @eth/nonce-being-mined))
|
||||
(log/infof "issue %s: reset nonce" issue-id)
|
||||
(reset! eth/nonce-being-mined nil)))
|
||||
(when (and (:timestamp @eth/nonce-being-mined)
|
||||
(t/before? (:timestamp @eth/nonce-being-mined) (t/minus (t/now) (t/minutes 5))))
|
||||
(log/errorf "nonce-being-mined not present in DB and unmined for 5 minutes, force reset. Tx hash: %s, type: %s"
|
||||
(:tx-hash @eth/nonce-being-mined) (:type @eth/nonce-being-mined))
|
||||
(reset! eth/nonce-being-mined nil))
|
||||
(log/info "Exit check-tx-receipts"))
|
||||
|
||||
(defn wrap-in-try-catch [func]
|
||||
(try
|
||||
@ -394,6 +414,7 @@
|
||||
update-confirm-hash
|
||||
update-payout-receipt
|
||||
update-watch-hash
|
||||
check-tx-receipts
|
||||
self-sign-bounty
|
||||
])
|
||||
(log/info "run-1-min-interval-tasks done")))
|
||||
|
Loading…
x
Reference in New Issue
Block a user