Add TxTracker protocol; introduce [un]track-tx! fns for generic tx
tracking
This commit is contained in:
parent
1f05659258
commit
ea406387dd
|
@ -150,31 +150,6 @@ SET transaction_hash = :transaction_hash,
|
||||||
WHERE issue_id = :issue_id;
|
WHERE issue_id = :issue_id;
|
||||||
|
|
||||||
|
|
||||||
-- TODO: this is terrible
|
|
||||||
-- :name update-contract-address :<! :1
|
|
||||||
-- :doc updates contract-address for a given issue
|
|
||||||
WITH t AS (
|
|
||||||
SELECT
|
|
||||||
i.issue_id AS issue_id,
|
|
||||||
i.issue_number AS issue_number,
|
|
||||||
i.title AS title,
|
|
||||||
i.transaction_hash AS transaction_hash,
|
|
||||||
i.contract_address AS contract_address,
|
|
||||||
i.comment_id AS comment_id,
|
|
||||||
i.repo_id AS repo_id,
|
|
||||||
r.owner AS owner,
|
|
||||||
r.repo AS repo
|
|
||||||
FROM issues i, repositories r
|
|
||||||
WHERE r.repo_id = i.repo_id
|
|
||||||
AND i.issue_id = :issue_id
|
|
||||||
)
|
|
||||||
UPDATE issues i
|
|
||||||
SET contract_address = :contract_address,
|
|
||||||
updated = timezone('utc'::text, now())
|
|
||||||
FROM t
|
|
||||||
WHERE i.issue_id = :issue_id
|
|
||||||
RETURNING t.issue_id, t.issue_number, t.title, t.transaction_hash, t.comment_id, i.contract_address, t.owner, t.repo, t.repo_id;
|
|
||||||
|
|
||||||
-- :name update-comment-id :! :n
|
-- :name update-comment-id :! :n
|
||||||
-- :doc updates comment-id for a given issue
|
-- :doc updates comment-id for a given issue
|
||||||
UPDATE issues
|
UPDATE issues
|
||||||
|
@ -242,7 +217,7 @@ WHERE pr_id = :pr_id;
|
||||||
-- Bounties ------------------------------------------------------------------------
|
-- Bounties ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
-- :name unmined-tx-hashes :? :*
|
-- :name unmined-txs :? :*
|
||||||
-- :doc hashes that haven't been mined for some time
|
-- :doc hashes that haven't been mined for some time
|
||||||
SELECT
|
SELECT
|
||||||
CASE WHEN transaction_hash is not null and contract_address is null
|
CASE WHEN transaction_hash is not null and contract_address is null
|
||||||
|
@ -268,22 +243,29 @@ AND (transaction_hash is not null and contract_address is null
|
||||||
OR execute_hash is not null and confirm_hash is null
|
OR execute_hash is not null and confirm_hash is null
|
||||||
OR watch_hash is not null);
|
OR watch_hash is not null);
|
||||||
|
|
||||||
|
-- :name save-tx-info! :! :n
|
||||||
-- :name reset-tx-hash! :! :n
|
-- :doc save tx hash from receipt
|
||||||
-- :doc reset tx hash if it hasn't been mined for some time
|
|
||||||
UPDATE issues
|
UPDATE issues
|
||||||
SET
|
SET
|
||||||
--~ (when (= (:type params) "deploy") "transaction_hash")
|
--~ (when (= (:type params) "deploy") "transaction_hash")
|
||||||
--~ (when (= (:type params) "execute") "execute_hash")
|
--~ (when (= (:type params) "execute") "execute_hash")
|
||||||
--~ (when (= (:type params) "watch") "watch_hash")
|
--~ (when (= (:type params) "watch") "watch_hash")
|
||||||
= null
|
= :tx-hash,
|
||||||
WHERE
|
updated = timezone('utc'::text, now())
|
||||||
--~ (when (= (:type params) "deploy") "transaction_hash")
|
WHERE issue_id=:issue-id
|
||||||
--~ (when (= (:type params) "execute") "execute_hash")
|
|
||||||
--~ (when (= (:type params) "watch") "watch_hash")
|
|
||||||
= :tx-hash
|
|
||||||
|
|
||||||
|
|
||||||
|
-- :name save-tx-result! :! :n
|
||||||
|
-- :doc save tx hash from receipt
|
||||||
|
UPDATE issues
|
||||||
|
SET
|
||||||
|
--~ (when (= (:type params) "deploy") "contract_address")
|
||||||
|
--~ (when (= (:type params) "execute") "confirm_hash")
|
||||||
|
--~ (when (= (:type params) "watch") "watch_hash")
|
||||||
|
= :result,
|
||||||
|
updated = timezone('utc'::text, now())
|
||||||
|
WHERE issue_id=:issue-id
|
||||||
|
|
||||||
-- :name pending-contracts :? :*
|
-- :name pending-contracts :? :*
|
||||||
-- :doc bounty issues where deploy contract has failed
|
-- :doc bounty issues where deploy contract has failed
|
||||||
SELECT
|
SELECT
|
||||||
|
@ -366,13 +348,6 @@ AND u.id = p.user_id
|
||||||
AND i.payout_receipt IS NULL
|
AND i.payout_receipt IS NULL
|
||||||
AND i.payout_hash IS NOT NULL;
|
AND i.payout_hash IS NOT NULL;
|
||||||
|
|
||||||
-- :name update-confirm-hash :! :n
|
|
||||||
-- :doc updates issue with confirmation hash
|
|
||||||
UPDATE issues
|
|
||||||
SET confirm_hash = :confirm_hash,
|
|
||||||
updated = timezone('utc'::text, now())
|
|
||||||
WHERE issue_id = :issue_id;
|
|
||||||
|
|
||||||
-- :name update-execute-hash :! :n
|
-- :name update-execute-hash :! :n
|
||||||
-- :doc updates issue with execute transaction hash
|
-- :doc updates issue with execute transaction hash
|
||||||
UPDATE issues
|
UPDATE issues
|
||||||
|
@ -385,12 +360,6 @@ UPDATE issues
|
||||||
SET winner_login = :winner_login
|
SET winner_login = :winner_login
|
||||||
WHERE issue_id = :issue_id;
|
WHERE issue_id = :issue_id;
|
||||||
|
|
||||||
-- :name update-watch-hash :! :n
|
|
||||||
-- :doc updates issue with watch transaction hash
|
|
||||||
UPDATE issues
|
|
||||||
SET watch_hash = :watch_hash
|
|
||||||
WHERE issue_id = :issue_id;
|
|
||||||
|
|
||||||
-- :name pending-watch-calls :? :*
|
-- :name pending-watch-calls :? :*
|
||||||
-- :doc issues with a pending watch transaction
|
-- :doc issues with a pending watch transaction
|
||||||
SELECT
|
SELECT
|
||||||
|
@ -459,6 +428,23 @@ FROM issues
|
||||||
WHERE repo_id = :repo_id
|
WHERE repo_id = :repo_id
|
||||||
AND issue_number = :issue_number;
|
AND issue_number = :issue_number;
|
||||||
|
|
||||||
|
-- :name get-issue-by-id :? :1
|
||||||
|
-- :doc get issue from DB by issue-id
|
||||||
|
SELECT
|
||||||
|
i.issue_id AS issue_id,
|
||||||
|
i.issue_number AS issue_number,
|
||||||
|
i.is_open AS is_open,
|
||||||
|
i.winner_login AS winner_login,
|
||||||
|
i.commit_sha AS commit_sha,
|
||||||
|
i.title AS title,
|
||||||
|
i.comment_id AS comment_id,
|
||||||
|
i.repo_id AS repo_id,
|
||||||
|
r.owner AS owner,
|
||||||
|
r.repo AS repo
|
||||||
|
FROM issues i, repositories r
|
||||||
|
WHERE r.repo_id = i.repo_id
|
||||||
|
AND i.issue_id = :issue-id
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- :name open-bounties :? :*
|
-- :name open-bounties :? :*
|
||||||
|
|
|
@ -25,18 +25,18 @@
|
||||||
(log/errorf "issue %s: Unable to deploy bounty contract because repo owner has no Ethereum addres" issue-id)
|
(log/errorf "issue %s: Unable to deploy bounty contract because repo owner has no Ethereum addres" issue-id)
|
||||||
(try
|
(try
|
||||||
(log/infof "issue %s: Deploying contract to %s" issue-id owner-address)
|
(log/infof "issue %s: Deploying contract to %s" issue-id owner-address)
|
||||||
(if-let [transaction-hash (multisig/deploy-multisig {:owner owner-address
|
(if-let [tx-info (multisig/deploy-multisig {:owner owner-address
|
||||||
:internal-tx-id (str "contract-github-issue-" issue-id)})]
|
:internal-tx-id [:deploy issue-id]})]
|
||||||
(do
|
(do
|
||||||
(log/infof "issue %s: Contract deployed, transaction-hash: %s" issue-id transaction-hash)
|
(log/infof "issue %s: Contract deployed, transaction-hash: %s" issue-id (:tx-hash tx-info))
|
||||||
(let [resp (github/post-deploying-comment owner
|
(let [resp (github/post-deploying-comment owner
|
||||||
repo
|
repo
|
||||||
issue-number
|
issue-number
|
||||||
transaction-hash)
|
(:tx-hash tx-info))
|
||||||
comment-id (:id resp)]
|
comment-id (:id resp)]
|
||||||
(log/infof "issue %s: post-deploying-comment response: %s" issue-id resp)
|
(log/infof "issue %s: post-deploying-comment response: %s" issue-id resp)
|
||||||
(issues/update-comment-id issue-id comment-id))
|
(issues/update-comment-id issue-id comment-id))
|
||||||
(issues/update-transaction-hash issue-id transaction-hash))
|
(eth/track-tx! tx-info))
|
||||||
(log/errorf "issue %s Failed to deploy contract to %s" issue-id owner-address))
|
(log/errorf "issue %s Failed to deploy contract to %s" issue-id owner-address))
|
||||||
(catch Exception ex (log/errorf ex "issue %s: deploy-contract exception" issue-id)))))
|
(catch Exception ex (log/errorf ex "issue %s: deploy-contract exception" issue-id)))))
|
||||||
|
|
||||||
|
|
|
@ -40,26 +40,12 @@
|
||||||
(jdbc/with-db-connection [con-db *db*]
|
(jdbc/with-db-connection [con-db *db*]
|
||||||
(db/confirmed-payouts con-db)))
|
(db/confirmed-payouts con-db)))
|
||||||
|
|
||||||
(defn update-confirm-hash
|
|
||||||
[issue-id confirm-hash]
|
|
||||||
(jdbc/with-db-connection [con-db *db*]
|
|
||||||
(db/update-confirm-hash con-db {:issue_id issue-id :confirm_hash confirm-hash})))
|
|
||||||
|
|
||||||
(defn update-execute-hash
|
|
||||||
[issue-id execute-hash]
|
|
||||||
(jdbc/with-db-connection [con-db *db*]
|
|
||||||
(db/update-execute-hash con-db {:issue_id issue-id :execute_hash execute-hash})))
|
|
||||||
|
|
||||||
(defn update-winner-login
|
(defn update-winner-login
|
||||||
[issue-id login]
|
[issue-id login]
|
||||||
(jdbc/with-db-connection [con-db *db*]
|
(jdbc/with-db-connection [con-db *db*]
|
||||||
(db/update-winner-login con-db {:issue_id issue-id :winner_login login})))
|
(db/update-winner-login con-db {:issue_id issue-id :winner_login login})))
|
||||||
|
|
||||||
(defn update-watch-hash
|
|
||||||
[issue-id watch-hash]
|
|
||||||
(jdbc/with-db-connection [con-db *db*]
|
|
||||||
(db/update-watch-hash con-db {:issue_id issue-id :watch_hash watch-hash})))
|
|
||||||
|
|
||||||
(defn pending-watch-calls
|
(defn pending-watch-calls
|
||||||
[]
|
[]
|
||||||
(jdbc/with-db-connection [con-db *db*]
|
(jdbc/with-db-connection [con-db *db*]
|
||||||
|
@ -101,11 +87,4 @@
|
||||||
(jdbc/with-db-connection [con-db *db*]
|
(jdbc/with-db-connection [con-db *db*]
|
||||||
(db/bounties-activity con-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})))
|
|
||||||
|
|
|
@ -38,19 +38,25 @@
|
||||||
:title title})))
|
:title title})))
|
||||||
|
|
||||||
|
|
||||||
(defn update-transaction-hash
|
(defn save-tx-info!
|
||||||
"Updates issue with transaction-hash"
|
"Set transaction_hash, execute_hash or watch_hash depending on operation"
|
||||||
[issue-id transaction-hash]
|
[issue-id tx-hash type-kw]
|
||||||
(jdbc/with-db-connection [con-db *db*]
|
(jdbc/with-db-connection [con-db *db*]
|
||||||
(db/update-transaction-hash con-db {:issue_id issue-id
|
(db/save-tx-info! con-db {:issue-id issue-id
|
||||||
:transaction_hash transaction-hash})))
|
:tx-hash tx-hash
|
||||||
|
:type (name type-kw)})))
|
||||||
|
|
||||||
(defn update-contract-address
|
(defn save-tx-result!
|
||||||
"Updates issue with contract-address"
|
"Set contract_address, confirm_hash or watch_hash depending on operation"
|
||||||
[issue-id contract-address]
|
[issue-id result type-kw]
|
||||||
(jdbc/with-db-connection [con-db *db*]
|
(jdbc/with-db-connection [con-db *db*]
|
||||||
(db/update-contract-address con-db {:issue_id issue-id
|
(db/save-tx-result! con-db {:issue-id issue-id
|
||||||
:contract_address contract-address})))
|
:result result
|
||||||
|
:type (name type-kw)})))
|
||||||
|
|
||||||
|
(defn unmined-txs []
|
||||||
|
(jdbc/with-db-connection [con-db *db*]
|
||||||
|
(db/unmined-txs con-db)))
|
||||||
|
|
||||||
(defn update-comment-id
|
(defn update-comment-id
|
||||||
"Updates issue with comment id"
|
"Updates issue with comment id"
|
||||||
|
@ -103,3 +109,8 @@
|
||||||
(jdbc/with-db-connection [con-db *db*]
|
(jdbc/with-db-connection [con-db *db*]
|
||||||
(db/get-issue con-db {:repo_id repo-id
|
(db/get-issue con-db {:repo_id repo-id
|
||||||
:issue_number issue-number})))
|
:issue_number issue-number})))
|
||||||
|
|
||||||
|
(defn get-issue-by-id
|
||||||
|
[issue-id]
|
||||||
|
(jdbc/with-db-connection [con-db *db*]
|
||||||
|
(db/get-issue-by-id con-db {:issue-id issue-id})))
|
||||||
|
|
|
@ -1,15 +1,16 @@
|
||||||
(ns commiteth.eth.core
|
(ns commiteth.eth.core
|
||||||
(:require [clojure.data.json :as json]
|
(:require [clojure.data.json :as json]
|
||||||
[org.httpkit.client :refer [post]]
|
[org.httpkit.client :refer [post]]
|
||||||
|
[commiteth.db.issues :as issues]
|
||||||
[clojure.java.io :as io]
|
[clojure.java.io :as io]
|
||||||
[commiteth.config :refer [env]]
|
[commiteth.config :refer [env]]
|
||||||
[clojure.string :refer [join]]
|
[clojure.string :refer [join]]
|
||||||
[taoensso.tufte :as tufte :refer (defnp p profiled profile)]
|
[taoensso.tufte :as tufte :refer (defnp p profiled profile)]
|
||||||
[clojure.tools.logging :as log]
|
[clojure.tools.logging :as log]
|
||||||
[clojure.string :as str]
|
[clojure.string :as str]
|
||||||
[clj-time.core :as t]
|
|
||||||
[mount.core :as mount]
|
|
||||||
[pandect.core :as pandect]
|
[pandect.core :as pandect]
|
||||||
|
[mount.core :as mount]
|
||||||
|
[clj-time.core :as t]
|
||||||
[commiteth.util.util :refer [json-api-request]])
|
[commiteth.util.util :refer [json-api-request]])
|
||||||
(:import [org.web3j
|
(:import [org.web3j
|
||||||
protocol.Web3j
|
protocol.Web3j
|
||||||
|
@ -52,37 +53,78 @@
|
||||||
(throw (ex-info "Make sure you provided proper credentials in appropriate resources/config.edn"
|
(throw (ex-info "Make sure you provided proper credentials in appropriate resources/config.edn"
|
||||||
{:password password :file-path file-path}))))))
|
{:password password :file-path file-path}))))))
|
||||||
|
|
||||||
(defrecord TxNonce [tx-hash nonce type timestamp])
|
|
||||||
(def nonce-being-mined (atom nil))
|
|
||||||
|
|
||||||
(defn get-nonce []
|
(defn get-nonce []
|
||||||
(let [nonce (.. (.ethGetTransactionCount @web3j-obj
|
(.. (.ethGetTransactionCount @web3j-obj
|
||||||
(env :eth-account)
|
(env :eth-account)
|
||||||
DefaultBlockParameterName/PENDING)
|
DefaultBlockParameterName/PENDING)
|
||||||
sendAsync
|
sendAsync
|
||||||
get
|
get
|
||||||
getTransactionCount)]
|
getTransactionCount))
|
||||||
(if (or (nil? @nonce-being-mined)
|
|
||||||
(> nonce (:nonce @nonce-being-mined)))
|
|
||||||
(:nonce (reset! nonce-being-mined (TxNonce. nil nonce nil nil)))
|
(defprotocol TxTracker
|
||||||
(throw (Exception. (str "Attempting to re-use old nonce" nonce))))))
|
(try-reserve-nonce [this])
|
||||||
|
(drop-nonce [this nonce])
|
||||||
|
(track-tx [this tx-info])
|
||||||
|
(untrack-tx [this tx-info])
|
||||||
|
(prune-txs [this unmined-txs])
|
||||||
|
)
|
||||||
|
|
||||||
|
(defrecord SequentialTxTracker [current-tx]
|
||||||
|
TxTracker
|
||||||
|
(try-reserve-nonce [this]
|
||||||
|
(let [nonce (get-nonce)]
|
||||||
|
(if (or (nil? @current-tx)
|
||||||
|
(> nonce (:nonce @current-tx)))
|
||||||
|
(:nonce (reset! current-tx {:nonce nonce}))
|
||||||
|
(throw (Exception. (str "Attempting to re-use old nonce" nonce))))))
|
||||||
|
(drop-nonce [this nonce]
|
||||||
|
(reset! current-tx nil))
|
||||||
|
(track-tx [this tx-info]
|
||||||
|
(reset! current-tx tx-info))
|
||||||
|
(untrack-tx [this tx-info]
|
||||||
|
(reset! current-tx nil))
|
||||||
|
(prune-txs [this unmined-txs]
|
||||||
|
(when (or ((set (map :tx-hash unmined-txs)) (:tx-hash @current-tx))
|
||||||
|
(and (:timestamp @current-tx)
|
||||||
|
(t/before? (:timestamp @current-tx) (t/minus (t/now) (t/minutes 5)))))
|
||||||
|
(log/errorf "Current nonce unmined for 5 minutes, force reset. Tx hash: %s, type: %s"
|
||||||
|
(:tx-hash @current-tx) (:type @current-tx))
|
||||||
|
(reset! current-tx nil)))
|
||||||
|
|
||||||
|
)
|
||||||
|
(def tx-tracker (SequentialTxTracker. (atom nil)))
|
||||||
|
|
||||||
|
(defn track-tx! [{:keys [issue-id tx-hash type]
|
||||||
|
:as tx-info}]
|
||||||
|
(track-tx tx-tracker tx-info)
|
||||||
|
(issues/save-tx-info! issue-id tx-hash type))
|
||||||
|
|
||||||
|
(defn untrack-tx! [{:keys [issue-id result type]
|
||||||
|
:as tx-info}]
|
||||||
|
(untrack-tx tx-tracker tx-info)
|
||||||
|
(issues/save-tx-result! issue-id result type))
|
||||||
|
|
||||||
|
(defn prune-txs! [unmined-txs]
|
||||||
|
(doseq [{issue-id :issue_id
|
||||||
|
tx-hash :tx_hash
|
||||||
|
type :type} unmined-txs]
|
||||||
|
(log/infof "issue %s: resetting tx operation: %s for hash: %s" issue-id type tx-hash)
|
||||||
|
(issues/save-tx-info! issue-id nil type))
|
||||||
|
(prune-txs tx-tracker unmined-txs))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
(defn get-signed-tx [gas-price gas-limit to data nonce]
|
(defn get-signed-tx [gas-price gas-limit to data nonce]
|
||||||
"Create a sign a raw transaction.
|
"Create a sign a raw transaction.
|
||||||
'From' argument is not needed as it's already
|
'From' argument is not needed as it's already
|
||||||
encoded in credentials.
|
encoded in credentials.
|
||||||
See https://web3j.readthedocs.io/en/latest/transactions.html#offline-transaction-signing"
|
See https://web3j.readthedocs.io/en/latest/transactions.html#offline-transaction-signing"
|
||||||
(let [tx (RawTransaction/createTransaction
|
(log/infof "Signing TX: nonce: %s, gas-price: %s, gas-limit: %s, data: %s"
|
||||||
nonce
|
nonce gas-price gas-limit data)
|
||||||
gas-price
|
(-> (RawTransaction/createTransaction nonce gas-price gas-limit to data)
|
||||||
gas-limit
|
(TransactionEncoder/signMessage (creds))
|
||||||
to
|
(Numeric/toHexString)))
|
||||||
data)
|
|
||||||
signed (TransactionEncoder/signMessage tx (creds))
|
|
||||||
hex-string (Numeric/toHexString signed)]
|
|
||||||
(log/infof "Signing TX: nonce: %s, gas-price: %s, gas-limit: %s, data: %s"
|
|
||||||
nonce gas-price gas-limit data)
|
|
||||||
hex-string))
|
|
||||||
|
|
||||||
|
|
||||||
(defn eth-gasstation-gas-price
|
(defn eth-gasstation-gas-price
|
||||||
|
@ -135,7 +177,9 @@
|
||||||
(defn eth-rpc
|
(defn eth-rpc
|
||||||
[{:keys [method params internal-tx-id]}]
|
[{:keys [method params internal-tx-id]}]
|
||||||
{:pre [(string? method) (some? params)]}
|
{:pre [(string? method) (some? params)]}
|
||||||
(let [request-id (swap! req-id-tracker inc)
|
(let [[type-kw issue-id] internal-tx-id
|
||||||
|
tx-id-str (str type-kw "-" issue-id)
|
||||||
|
request-id (swap! req-id-tracker inc)
|
||||||
body {:jsonrpc "2.0"
|
body {:jsonrpc "2.0"
|
||||||
:method method
|
:method method
|
||||||
:params params
|
:params params
|
||||||
|
@ -145,10 +189,10 @@
|
||||||
response @(post (eth-rpc-url) options)
|
response @(post (eth-rpc-url) options)
|
||||||
result (safe-read-str (:body response))]
|
result (safe-read-str (:body response))]
|
||||||
(when internal-tx-id
|
(when internal-tx-id
|
||||||
(log/infof "%s: eth-rpc %s" internal-tx-id method))
|
(log/infof "%s: eth-rpc %s" tx-id-str method))
|
||||||
(log/debugf "%s: eth-rpc req(%s) body: %s" internal-tx-id request-id body)
|
(log/debugf "%s: eth-rpc req(%s) body: %s" tx-id-str request-id body)
|
||||||
(if internal-tx-id
|
(if tx-id-str
|
||||||
(log/infof "%s: eth-rpc req(%s) result: %s" internal-tx-id request-id result)
|
(log/infof "%s: eth-rpc req(%s) result: %s" tx-id-str request-id result)
|
||||||
(log/debugf "no-tx-id: eth-rpc req(%s) result: %s" request-id result))
|
(log/debugf "no-tx-id: eth-rpc req(%s) result: %s" request-id result))
|
||||||
(cond
|
(cond
|
||||||
;; Ignore any responses that have mismatching request ID
|
;; Ignore any responses that have mismatching request ID
|
||||||
|
@ -159,7 +203,7 @@
|
||||||
(:error result)
|
(:error result)
|
||||||
(throw
|
(throw
|
||||||
(ex-info (format "%s: Error submitting transaction via eth-rpc %s"
|
(ex-info (format "%s: Error submitting transaction via eth-rpc %s"
|
||||||
(or internal-tx-id "(no-tx-id)") (:error result))
|
(or tx-id-str "(no-tx-id)") (:error result))
|
||||||
(:error result)))
|
(:error result)))
|
||||||
|
|
||||||
:else
|
:else
|
||||||
|
@ -243,13 +287,8 @@
|
||||||
|
|
||||||
(defn get-transaction-receipt
|
(defn get-transaction-receipt
|
||||||
[hash]
|
[hash]
|
||||||
(when-let [receipt (eth-rpc {:method "eth_getTransactionReceipt"
|
(eth-rpc {:method "eth_getTransactionReceipt"
|
||||||
:params [hash]})]
|
: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
|
(defn format-call-params
|
||||||
[method-id & params]
|
[method-id & params]
|
||||||
|
@ -262,47 +301,68 @@
|
||||||
(eth-rpc {:method "eth_call"
|
(eth-rpc {:method "eth_call"
|
||||||
:params [{:to contract :data data} "latest"]})))
|
:params [{:to contract :data data} "latest"]})))
|
||||||
|
|
||||||
(defn execute
|
(defn construct-params
|
||||||
[{:keys [from contract method-id gas-limit params internal-tx-id type]}]
|
[{:keys [from contract method-id params gas-price]}]
|
||||||
{:pre [(string? method-id)]}
|
|
||||||
(let [data (apply format-call-params method-id params)
|
(let [data (apply format-call-params method-id params)
|
||||||
gas-price (gas-price)
|
value (format "0x%x" 0)]
|
||||||
value (format "0x%x" 0)
|
(cond-> {:data data
|
||||||
params (cond-> {:data data
|
:from from
|
||||||
:from from
|
:value value}
|
||||||
:value value}
|
gas-price
|
||||||
gas-price
|
(merge {:gasPrice (integer->hex gas-price)})
|
||||||
(merge {:gasPrice (integer->hex gas-price)})
|
contract
|
||||||
contract
|
(merge {:to contract}))))
|
||||||
(merge {:to contract}))
|
|
||||||
|
(defmulti execute (fn [arg] (offline-signing?)))
|
||||||
|
|
||||||
|
|
||||||
|
(defmethod execute true
|
||||||
|
[{:keys [from contract method-id gas-limit params internal-tx-id]
|
||||||
|
:as args}]
|
||||||
|
{:pre [(string? method-id)]}
|
||||||
|
(let [[type-kw issue-id] internal-tx-id
|
||||||
|
nonce (try-reserve-nonce tx-tracker)
|
||||||
|
gas-price (gas-price)
|
||||||
|
params (construct-params (assoc args :gas-price gas-price))
|
||||||
|
gas (or gas-limit (estimate-gas from contract (:value params) params))
|
||||||
|
params (get-signed-tx (biginteger gas-price)
|
||||||
|
(hex->big-integer gas)
|
||||||
|
contract
|
||||||
|
(:data params)
|
||||||
|
nonce)
|
||||||
|
tx-hash (try
|
||||||
|
(eth-rpc
|
||||||
|
{:method "eth_sendRawTransaction"
|
||||||
|
:params [params]
|
||||||
|
:internal-tx-id internal-tx-id})
|
||||||
|
(catch Throwable ex
|
||||||
|
(drop-nonce tx-tracker nonce)
|
||||||
|
(throw ex)))]
|
||||||
|
{:tx-hash tx-hash
|
||||||
|
:issue-id issue-id
|
||||||
|
:type type-kw
|
||||||
|
:nonce nonce
|
||||||
|
:timestamp (t/now)}))
|
||||||
|
|
||||||
|
(defmethod execute false
|
||||||
|
[{:keys [from contract method-id gas-limit params internal-tx-id]
|
||||||
|
:as args}]
|
||||||
|
{:pre [(string? method-id)]}
|
||||||
|
(let [[type-kw issue-id] internal-tx-id
|
||||||
|
gas-price (gas-price)
|
||||||
|
params (construct-params (assoc args :gas-price gas-price))
|
||||||
|
gas (or gas-limit (estimate-gas from contract (:value params) params))
|
||||||
|
params (assoc params :gas gas)
|
||||||
|
tx-hash (eth-rpc
|
||||||
|
{:method "personal_sendTransaction"
|
||||||
|
:params [params (eth-password)]
|
||||||
|
:internal-tx-id internal-tx-id})]
|
||||||
|
{:tx-hash tx-hash
|
||||||
|
:type type-kw
|
||||||
|
:timestamp (t/now)
|
||||||
|
:issue-id issue-id}
|
||||||
|
))
|
||||||
|
|
||||||
gas (if gas-limit gas-limit
|
|
||||||
(estimate-gas from contract value params))
|
|
||||||
nonce (when (offline-signing?) (get-nonce))
|
|
||||||
params (if (offline-signing?)
|
|
||||||
(get-signed-tx (biginteger gas-price)
|
|
||||||
(hex->big-integer gas)
|
|
||||||
contract
|
|
||||||
data
|
|
||||||
nonce)
|
|
||||||
(assoc params :gas gas))]
|
|
||||||
(if (offline-signing?)
|
|
||||||
(try
|
|
||||||
(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
|
|
||||||
(reset! nonce-being-mined nil)
|
|
||||||
(throw ex)))
|
|
||||||
(eth-rpc
|
|
||||||
{:method "personal_sendTransaction"
|
|
||||||
:params [params (eth-password)]
|
|
||||||
:internal-tx-id internal-tx-id}))))
|
|
||||||
|
|
||||||
(defn hex-ch->num
|
(defn hex-ch->num
|
||||||
[ch]
|
[ch]
|
||||||
|
|
|
@ -41,9 +41,8 @@
|
||||||
`internal-tx-id` is used to identify what issue this multisig is deployed
|
`internal-tx-id` is used to identify what issue this multisig is deployed
|
||||||
for and manage nonces at a later point in time."
|
for and manage nonces at a later point in time."
|
||||||
[{:keys [owner internal-tx-id]}]
|
[{:keys [owner internal-tx-id]}]
|
||||||
{:pre [(string? owner) (string? internal-tx-id)]}
|
{:pre [(string? owner) (vector? internal-tx-id)]}
|
||||||
(eth/execute {:internal-tx-id internal-tx-id
|
(eth/execute {:internal-tx-id internal-tx-id
|
||||||
:type "deploy"
|
|
||||||
:from (eth/eth-account)
|
:from (eth/eth-account)
|
||||||
:contract (factory-contract-addr)
|
:contract (factory-contract-addr)
|
||||||
:method-id (:create method-ids)
|
:method-id (:create method-ids)
|
||||||
|
@ -88,13 +87,12 @@
|
||||||
|
|
||||||
(defn send-all
|
(defn send-all
|
||||||
[{:keys [contract payout-address internal-tx-id]}]
|
[{:keys [contract payout-address internal-tx-id]}]
|
||||||
{:pre [(string? contract) (string? payout-address) (string? internal-tx-id)]}
|
{:pre [(string? contract) (string? payout-address) (vector? internal-tx-id)]}
|
||||||
(log/debug "multisig/send-all " contract payout-address internal-tx-id)
|
(log/debug "multisig/send-all " contract payout-address internal-tx-id)
|
||||||
(let [params (eth/format-call-params
|
(let [params (eth/format-call-params
|
||||||
(:withdraw-everything method-ids)
|
(:withdraw-everything method-ids)
|
||||||
payout-address)]
|
payout-address)]
|
||||||
(eth/execute {:internal-tx-id internal-tx-id
|
(eth/execute {:internal-tx-id internal-tx-id
|
||||||
:type "execute"
|
|
||||||
:from (eth/eth-account)
|
:from (eth/eth-account)
|
||||||
:contract contract
|
:contract contract
|
||||||
:method-id (:submit-transaction method-ids)
|
:method-id (:submit-transaction method-ids)
|
||||||
|
@ -108,12 +106,11 @@
|
||||||
(:address token-details)))
|
(:address token-details)))
|
||||||
|
|
||||||
(defn watch-token
|
(defn watch-token
|
||||||
[bounty-addr token]
|
[{:keys [bounty-addr token internal-tx-id]}]
|
||||||
(log/debug "multisig/watch-token" bounty-addr token)
|
(log/debug "multisig/watch-token" bounty-addr token)
|
||||||
(let [token-address (get-token-address token)]
|
(let [token-address (get-token-address token)]
|
||||||
(assert token-address)
|
(assert token-address)
|
||||||
(eth/execute {:internal-tx-id (str "watch-token-" (System/currentTimeMillis) "-" bounty-addr)
|
(eth/execute {:internal-tx-id internal-tx-id
|
||||||
:type "watch"
|
|
||||||
:from (eth/eth-account)
|
:from (eth/eth-account)
|
||||||
:contract bounty-addr
|
:contract bounty-addr
|
||||||
:method-id (:watch method-ids)
|
:method-id (:watch method-ids)
|
||||||
|
|
|
@ -52,11 +52,14 @@
|
||||||
(when-let [receipt (eth/get-transaction-receipt transaction-hash)]
|
(when-let [receipt (eth/get-transaction-receipt transaction-hash)]
|
||||||
(log/infof "issue %s: update-issue-contract-address: tx receipt: %s" issue-id receipt)
|
(log/infof "issue %s: update-issue-contract-address: tx receipt: %s" issue-id receipt)
|
||||||
(if-let [contract-address (multisig/find-created-multisig-address receipt)]
|
(if-let [contract-address (multisig/find-created-multisig-address receipt)]
|
||||||
(let [issue (issues/update-contract-address issue-id contract-address)
|
(let [_ (eth/untrack-tx! {:issue-id issue-id
|
||||||
|
:tx-hash transaction-hash
|
||||||
|
:result contract-address
|
||||||
|
:type :deploy})
|
||||||
{owner :owner
|
{owner :owner
|
||||||
repo :repo
|
repo :repo
|
||||||
comment-id :comment_id
|
comment-id :comment_id
|
||||||
issue-number :issue_number} issue
|
issue-number :issue_number} (issues/get-issue-by-id issue-id)
|
||||||
balance-eth-str (eth/get-balance-eth contract-address 6)
|
balance-eth-str (eth/get-balance-eth contract-address 6)
|
||||||
balance-eth (read-string balance-eth-str)]
|
balance-eth (read-string balance-eth-str)]
|
||||||
(log/infof "issue %s: Updating comment image" issue-id)
|
(log/infof "issue %s: Updating comment image" issue-id)
|
||||||
|
@ -112,7 +115,7 @@
|
||||||
issue-number :issue_number
|
issue-number :issue_number
|
||||||
balance-eth :balance_eth
|
balance-eth :balance_eth
|
||||||
tokens :tokens
|
tokens :tokens
|
||||||
winner-login :winner_login} (db-bounties/pending-bounties)]
|
winner-login :winner_login} (db-bounties/pending-bounties)]
|
||||||
(try
|
(try
|
||||||
(let [value (eth/get-balance-hex contract-address)]
|
(let [value (eth/get-balance-hex contract-address)]
|
||||||
(if (empty? payout-address)
|
(if (empty? payout-address)
|
||||||
|
@ -126,11 +129,11 @@
|
||||||
tokens
|
tokens
|
||||||
winner-login
|
winner-login
|
||||||
true))
|
true))
|
||||||
(let [execute-hash (multisig/send-all {:contract contract-address
|
(let [tx-info (multisig/send-all {:contract contract-address
|
||||||
:payout-address payout-address
|
:payout-address payout-address
|
||||||
:internal-tx-id (str "payout-github-issue-" issue-id)})]
|
:internal-tx-id [:execute issue-id]})]
|
||||||
(log/infof "issue %s: Payout self-signed, called sign-all(%s) tx: %s" issue-id contract-address payout-address execute-hash)
|
(log/infof "issue %s: Payout self-signed, called sign-all(%s) tx: %s" issue-id contract-address payout-address (:tx-hash tx-info))
|
||||||
(db-bounties/update-execute-hash issue-id execute-hash)
|
(eth/track-tx! tx-info)
|
||||||
(db-bounties/update-winner-login issue-id winner-login)
|
(db-bounties/update-winner-login issue-id winner-login)
|
||||||
(github/update-merged-issue-comment owner
|
(github/update-merged-issue-comment owner
|
||||||
repo
|
repo
|
||||||
|
@ -157,7 +160,10 @@
|
||||||
(log/infof "issue %s: execution receipt for issue " issue-id receipt)
|
(log/infof "issue %s: execution receipt for issue " issue-id receipt)
|
||||||
(when-let [confirm-hash (multisig/find-confirmation-tx-id receipt)]
|
(when-let [confirm-hash (multisig/find-confirmation-tx-id receipt)]
|
||||||
(log/infof "issue %s: confirm hash:" issue-id confirm-hash)
|
(log/infof "issue %s: confirm hash:" issue-id confirm-hash)
|
||||||
(db-bounties/update-confirm-hash issue-id confirm-hash)))
|
(eth/untrack-tx! {:issue-id issue-id
|
||||||
|
:tx-hash execute-hash
|
||||||
|
:result confirm-hash
|
||||||
|
:type :execute})))
|
||||||
(catch Throwable ex
|
(catch Throwable ex
|
||||||
(log/errorf ex "issue %s: update-confirm-hash exception:" issue-id)))))
|
(log/errorf ex "issue %s: update-confirm-hash exception:" issue-id)))))
|
||||||
(log/info "Exit update-confirm-hash"))
|
(log/info "Exit update-confirm-hash"))
|
||||||
|
@ -172,7 +178,10 @@
|
||||||
(log/infof "issue %s: pending watch call %s" issue-id watch-hash)
|
(log/infof "issue %s: pending watch call %s" issue-id watch-hash)
|
||||||
(try
|
(try
|
||||||
(when-let [receipt (eth/get-transaction-receipt watch-hash)]
|
(when-let [receipt (eth/get-transaction-receipt watch-hash)]
|
||||||
(db-bounties/update-watch-hash issue-id nil))
|
(eth/untrack-tx! {:issue-id issue-id
|
||||||
|
:tx-hash watch-hash
|
||||||
|
:result nil
|
||||||
|
:type :watch}))
|
||||||
(catch Throwable ex
|
(catch Throwable ex
|
||||||
(log/errorf ex "issue %s: update-watch-hash exception:" issue-id))))))
|
(log/errorf ex "issue %s: update-watch-hash exception:" issue-id))))))
|
||||||
|
|
||||||
|
@ -260,8 +269,10 @@
|
||||||
(when (and (nil? watch-hash)
|
(when (and (nil? watch-hash)
|
||||||
(not= balance internal-balance))
|
(not= balance internal-balance))
|
||||||
(log/infof "bounty %s: balances not in sync, calling watch" bounty-addr)
|
(log/infof "bounty %s: balances not in sync, calling watch" bounty-addr)
|
||||||
(let [hash (multisig/watch-token bounty-addr tla)]
|
(let [tx-info (multisig/watch-token {:bounty-addr bounty-addr
|
||||||
(db-bounties/update-watch-hash issue-id hash)))))))
|
:token tla
|
||||||
|
:internal-tx-id [:watch issue-id]})]
|
||||||
|
(eth/track-tx! tx-info)))))))
|
||||||
(catch Throwable ex
|
(catch Throwable ex
|
||||||
(log/error ex "bounty %s: update-bounty-token-balances exception" bounty-addr))))
|
(log/error ex "bounty %s: update-bounty-token-balances exception" bounty-addr))))
|
||||||
(log/info "Exit update-bounty-token-balances"))
|
(log/info "Exit update-bounty-token-balances"))
|
||||||
|
@ -376,19 +387,7 @@
|
||||||
as we are executing txs sequentially"
|
as we are executing txs sequentially"
|
||||||
[]
|
[]
|
||||||
(log/info "In check-tx-receipts")
|
(log/info "In check-tx-receipts")
|
||||||
(doseq [{tx-hash :tx_hash
|
(eth/prune-txs! (issues/unmined-txs))
|
||||||
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"))
|
(log/info "Exit check-tx-receipts"))
|
||||||
|
|
||||||
(defn wrap-in-try-catch [func]
|
(defn wrap-in-try-catch [func]
|
||||||
|
|
Loading…
Reference in New Issue