|
4 | 4 |
|
5 | 5 | https://github.com/ConsenSys/eth-testrpc |
6 | 6 | """ |
| 7 | +import time |
| 8 | +import Queue |
| 9 | +import threading |
| 10 | +import uuid |
7 | 11 |
|
8 | 12 |
|
9 | 13 | from ethereum import utils as ethereum_utils |
@@ -121,10 +125,34 @@ class EthTesterClient(object): |
121 | 125 | Stand-in replacement for the rpc client that speaks directly to the |
122 | 126 | `ethereum.tester` facilities. |
123 | 127 | """ |
124 | | - def __init__(self): |
| 128 | + def __init__(self, async=True, async_timeout=10): |
125 | 129 | self.evm = t.state() |
126 | 130 | self.evm.mine() |
127 | 131 |
|
| 132 | + self.is_async = async |
| 133 | + self.async_timeout = async_timeout |
| 134 | + |
| 135 | + if self.is_async: |
| 136 | + self.request_queue = Queue.Queue() |
| 137 | + self.results = {} |
| 138 | + |
| 139 | + self.request_thread = threading.Thread(target=self.process_requests) |
| 140 | + self.request_thread.daemon = True |
| 141 | + self.request_thread.start() |
| 142 | + |
| 143 | + def process_requests(self): |
| 144 | + while True: |
| 145 | + id, args, kwargs = self.request_queue.get() |
| 146 | + mine = kwargs.pop('_mine', False) |
| 147 | + try: |
| 148 | + self._send_transaction(*args, **kwargs) |
| 149 | + if mine: |
| 150 | + self.evm.mine() |
| 151 | + response = self.evm.last_tx.hash |
| 152 | + except ValueError as e: |
| 153 | + response = e |
| 154 | + self.results[id] = response |
| 155 | + |
128 | 156 | def wait_for_block(self, block_number, max_wait=0): |
129 | 157 | while self.evm.block.number < block_number: |
130 | 158 | self.evm.mine() |
@@ -177,9 +205,34 @@ def _send_transaction(self, _from=None, to=None, gas=None, gas_price=None, |
177 | 205 | return self.evm.send(sender=sender, to=to, value=value, evmdata=data) |
178 | 206 |
|
179 | 207 | def send_transaction(self, *args, **kwargs): |
180 | | - self._send_transaction(*args, **kwargs) |
181 | | - self.evm.mine() |
182 | | - return self.evm.last_tx.hash |
| 208 | + if self.is_async: |
| 209 | + kwargs['_mine'] = True |
| 210 | + request_id = uuid.uuid4() |
| 211 | + self.request_queue.put((request_id, args, kwargs)) |
| 212 | + start = time.time() |
| 213 | + while time.time() - start < self.async_timeout: |
| 214 | + if request_id in self.results: |
| 215 | + return self.results.pop(request_id) |
| 216 | + raise ValueError("Timeout waiting for {0}".format(request_id)) |
| 217 | + else: |
| 218 | + self._send_transaction(*args, **kwargs) |
| 219 | + self.evm.mine() |
| 220 | + return self.evm.last_tx.hash |
| 221 | + |
| 222 | + def make_ipc_request(self, *args, **kwargs): |
| 223 | + if self.is_async: |
| 224 | + request_id = uuid.uuid4() |
| 225 | + self.request_queue.put((request_id, args, kwargs)) |
| 226 | + start = time.time() |
| 227 | + while time.time() - start < 10: |
| 228 | + if request_id in self.results: |
| 229 | + result = self.results.pop(request_id) |
| 230 | + if isinstance(result, Exception): |
| 231 | + raise result |
| 232 | + return result |
| 233 | + raise ValueError("Timeout waiting for {0}".format(request_id)) |
| 234 | + else: |
| 235 | + return self._make_ipc_request(*args, **kwargs) |
183 | 236 |
|
184 | 237 | def _get_transaction_by_hash(self, txn_hash): |
185 | 238 | txn_hash = strip_0x(txn_hash) |
|
0 commit comments