Repository: eth-brownie/brownie
Issue: `@trace_property` methods give confusing error on deployment transactions

### Overview
Brownie does not currently support traces for transactions that deploy contracts. Calling any method that requires a trace returns an `AttributeError`.  It should instead return a meaningful error explaining that traces are not available, so this information is not available.


Changed files:
brownie/network/transaction.py, brownie/network/contract.py

diff --git a/brownie/network/contract.py b/brownie/network/contract.py
index b1b97688..f86fa3b8 100644
--- a/brownie/network/contract.py
+++ b/brownie/network/contract.py
@@ -184,7 +184,7 @@ class ContractContainer(_ContractBase):
 
     def _add_from_tx(self, tx: TransactionReceiptType) -> None:
         tx._confirmed.wait()
-        if tx.status:
+        if tx.status and tx.contract_address is not None:
             try:
                 self.at(tx.contract_address, tx.sender, tx)
             except ContractNotFound:
diff --git a/brownie/network/transaction.py b/brownie/network/transaction.py
index a2bea3e9..7abaa99d 100644
--- a/brownie/network/transaction.py
+++ b/brownie/network/transaction.py
@@ -34,6 +34,8 @@ def trace_property(fn: Callable) -> Any:
     def wrapper(self: "TransactionReceipt") -> Any:
         if self.status == -1:
             return None
+        if self._trace_exc is not None:
+            raise self._trace_exc
         return fn(self)
 
     return wrapper
@@ -90,39 +92,6 @@ class TransactionReceipt:
         revert_msg: Error string from reverted contract all
         modified_state: Boolean, did this contract write to storage?"""
 
-    __slots__ = (
-        "_call_cost",
-        "_confirmed",
-        "_events",
-        "_internal_transfers",
-        "_modified_state",
-        "_new_contracts",
-        "_raw_trace",
-        "_return_value",
-        "_revert_msg",
-        "_revert_pc",
-        "_silent",
-        "_trace",
-        "_trace_origin",
-        "block_number",
-        "contract_address",
-        "contract_name",
-        "coverage_hash",
-        "fn_name",
-        "gas_limit",
-        "gas_price",
-        "gas_used",
-        "input",
-        "logs",
-        "nonce",
-        "receiver",
-        "sender",
-        "status",
-        "txid",
-        "txindex",
-        "value",
-    )
-
     def __init__(
         self,
         txid: Union[str, bytes],
@@ -151,6 +120,8 @@ class TransactionReceipt:
         if not self._silent:
             print(f"Transaction sent: {color('bright blue')}{txid}{color}")
 
+        # internal attributes
+        self._trace_exc = None
         self._trace_origin = None
         self._raw_trace = None
         self._trace = None
@@ -163,9 +134,19 @@ class TransactionReceipt:
         self._internal_transfers = None
         self._confirmed = threading.Event()
 
+        # attributes that cannot be set until the tx confirms
+        self.block_number = None
+        self.contract_address: Optional[str] = None
+        self.gas_used = None
+        self.logs = None
+        self.nonce = None
+        self.txindex = None
+
+        # attributes that can be set immediately
         self.sender = sender
         self.status = -1
         self.txid = txid
+        self.contract_name = None
         self.fn_name = name
 
         if name and "." in name:
@@ -193,12 +174,6 @@ class TransactionReceipt:
     def __hash__(self) -> int:
         return hash(self.txid)
 
-    def __getattr__(self, attr: str) -> Any:
-        if attr not in self.__slots__:
-            raise AttributeError(f"'TransactionReceipt' object has no attribute '{attr}'")
-        if self.status == -1:
-            return None
-
     @trace_property
     def events(self) -> Optional[List]:
         if not self.status:
@@ -329,7 +304,7 @@ class TransactionReceipt:
         # await first confirmation
         receipt = web3.eth.waitForTransactionReceipt(self.txid, timeout=None, poll_latency=0.5)
 
-        self.block_number: Optional[int] = receipt["blockNumber"]
+        self.block_number = receipt["blockNumber"]
         # wait for more confirmations if required and handle uncle blocks
         remaining_confs = required_confs
         while remaining_confs > 0 and required_confs > 1:
@@ -444,8 +419,10 @@ class TransactionReceipt:
             raise RPCRequestError(msg) from None
 
         if "error" in trace:
-            self.modified_state = None
-            raise RPCRequestError(trace["error"]["message"])
+            self._modified_state = None
+            self._trace_exc = RPCRequestError(trace["error"]["message"])
+            raise self._trace_exc
+
         self._raw_trace = trace = trace["result"]["structLogs"]
         if not trace:
             self._modified_state = False