Skip to content

Commit

Permalink
Merge pull request #846 from eth-brownie/feat-replace-tx
Browse files Browse the repository at this point in the history
Allow replacing pending transactions
  • Loading branch information
iamdefinitelyahuman committed Nov 16, 2020
2 parents 3fad0bd + f8439f0 commit b7c7253
Show file tree
Hide file tree
Showing 8 changed files with 211 additions and 53 deletions.
18 changes: 17 additions & 1 deletion brownie/network/account.py
Original file line number Diff line number Diff line change
Expand Up @@ -451,10 +451,16 @@ def deploy(
self,
silent=silent,
required_confs=required_confs,
is_blocking=False,
name=contract._name + ".constructor",
revert_data=revert_data,
)
# add the TxHistory before waiting for confirmation, this way the tx
# object is available if the user CTRL-C to stop waiting in the console
history._add_tx(receipt)
if required_confs > 0:
receipt._confirmed.wait()

add_thread = threading.Thread(target=contract._add_from_tx, args=(receipt,), daemon=True)
add_thread.start()

Expand Down Expand Up @@ -585,9 +591,19 @@ def transfer(
revert_data = (exc.revert_msg, exc.pc, exc.revert_type)

receipt = TransactionReceipt(
txid, self, required_confs=required_confs, silent=silent, revert_data=revert_data
txid,
self,
required_confs=required_confs,
is_blocking=False,
silent=silent,
revert_data=revert_data,
)
# add the TxHistory before waiting for confirmation, this way the tx
# object is available if the user CTRL-C to stop waiting in the console
history._add_tx(receipt)
if required_confs > 0:
receipt._confirmed.wait()

if rpc.is_active():
undo_thread = threading.Thread(
target=Chain()._add_to_undo_buffer,
Expand Down
13 changes: 8 additions & 5 deletions brownie/network/event.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,14 @@ class EventDict:
Dict/list hybrid container, base class for all events fired in a transaction.
"""

def __init__(self, events: List) -> None:
def __init__(self, events: Optional[List] = None) -> None:
"""Instantiates the class.
Args:
events: event data as supplied by eth_event.decode_logs or eth_event.decode_trace"""
if events is None:
events = []

self._ordered = [
_EventItem(
i["name"],
Expand Down Expand Up @@ -208,9 +211,9 @@ def _add_deployment_topics(address: str, abi: List) -> None:
_deployment_topics[address] = eth_event.get_topic_map(abi)


def _decode_logs(logs: List) -> Union["EventDict", List[None]]:
def _decode_logs(logs: List) -> EventDict:
if not logs:
return []
return EventDict()

idx = 0
events: List = []
Expand All @@ -237,9 +240,9 @@ def _decode_logs(logs: List) -> Union["EventDict", List[None]]:
return EventDict(events)


def _decode_trace(trace: Sequence, initial_address: str) -> Union["EventDict", List[None]]:
def _decode_trace(trace: Sequence, initial_address: str) -> EventDict:
if not trace:
return []
return EventDict()

events = eth_event.decode_traceTransaction(
trace, _topics, allow_undecoded=True, initial_address=initial_address
Expand Down
19 changes: 18 additions & 1 deletion brownie/network/state.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,13 @@ def __repr__(self) -> str:
return str(self._list)
return super().__repr__()

def __getattribute__(self, name: str) -> Any:
# filter dropped transactions prior to attribute access
items = super().__getattribute__("_list")
items = [i for i in items if i.status != -2]
setattr(self, "_list", items)
return super().__getattribute__(name)

def __bool__(self) -> bool:
return bool(self._list)

Expand All @@ -68,6 +75,14 @@ def _revert(self, height: int) -> None:

def _add_tx(self, tx: TransactionReceipt) -> None:
self._list.append(tx)
confirm_thread = threading.Thread(target=self._await_confirm, args=(tx,), daemon=True)
confirm_thread.start()

def _await_confirm(self, tx: TransactionReceipt) -> None:
# in case of multiple tx's with the same nonce, remove the dropped tx's upon confirmation
tx._confirmed.wait()
for dropped_tx in self.filter(sender=tx.sender, nonce=tx.nonce, key=lambda k: k != tx):
self._list.remove(dropped_tx)

def clear(self) -> None:
self._list.clear()
Expand All @@ -76,7 +91,9 @@ def copy(self) -> List:
"""Returns a shallow copy of the object as a list"""
return self._list.copy()

def filter(self, key: Optional[Callable] = None, **kwargs: Dict) -> List:
def filter(
self, key: Optional[Callable] = None, **kwargs: Optional[Any]
) -> List[TransactionReceipt]:
"""
Return a filtered list of transactions.
Expand Down
Loading

0 comments on commit b7c7253

Please sign in to comment.