Если вы выполнили первую и вторую части, у вас будет полностью настроенная regtest среда. Теперь у вас есть все, что угодно, чтобы экспериментировать с любой безумной идеей, которая вам придет в голову.
Вперед за програмным материалом
Я собираюсь упростить задачу, создав простой скрипт python3, который создает необработанную транзакцию, подписывает транзакцию и, наконец, отправляет все это из программы Python:
from bitcoinrpc.authproxy import AuthServiceProxy, JSONRPCException
import sys
rpc_connection = AuthServiceProxy("http://%s:%[email protected]:18444"%("bitcoin", "talk"),timeout = 120)
def addreses_to_spent_from():
lstSpendableAddresses = []
allAddresses = rpc_connection.listaddressgroupings()
for i in range(0, len(allAddresses)):
availableBTC = float(allAddresses[i][0][1])
if availableBTC > 1:
print('Suitable address found: %s' % allAddresses[i][0][0])
lstSpendableAddresses.append(allAddresses[i][0][0])
return lstSpendableAddresses
def make_transaction(txid, idx, address, amount):
raw = rpc_connection.createrawtransaction(
[{"txid": txid,
"vout": idx}],
{address:amount} )
signed = rpc_connection.signrawtransactionwithwallet(raw)
send_result = rpc_connection.sendrawtransaction(signed['hex'])
return send_result
#=============
txid = None
for address in addreses_to_spent_from():
unspents = rpc_connection.listunspent(1, 99999999, [address])
num_unspents = len(unspents)
for spendable_input in unspents:
txid = spendable_input['txid']
idx = spendable_input['vout']
amount = float(spendable_input['amount'])
if amount > 1:
break;
if txid == None:
sys.exit('No suitable input could be found for a transaction!')
trans_amount = float(amount) - (0.00000100)
trans_amount = "{:.8f}".format(trans_amount)
non_wallet_address = 'mpXwg4jMtRhuSpVq4xS3HFHmCmWp9NyGKt'
success_txid = make_transaction(txid, idx, non_wallet_address, trans_amount)
print('Transaction-id: %s' % success_txid)
Программа ищет подходящий адрес кошелька, в котором есть как минимум 1 неизрасходованный BTC. Первый найденный используется для получения входных данных для нашей транзакции. Весь ввод тратится за вычетом комиссий (в данном примере установлено фиксированное значение 0.00000100)). Функция "make_transaction" заботится о подписании и отправке транзакции и возвращает txid в случае успеха). Повторюсь еще раз: речь идет о примере того, как можно самостоятельно использовать regtest среду для программного эксперимента/тестирования. Я уверен, что вы можете придумать много вещей, которые содержат ошибки в моем примере кода, это нормально . Все дело в концепции regtest, а не в моих слабых навыках программирования!
При запуске кода вы должны получить что-то вроде этого:
Suitable address found: bcrt1qkcvk53y8qfckuwemp7w9hahszk6j5eeqjae9t4
Transaction-id: c784407fed108736c9a71d9ab2eb22ce1bf46c1ec9006d75e8a28671af86d1ae
И вот ты только что перевел 50 BTC (минус комиссия) на адрес, который не твой и не в твоем кошельке. И если ты пожалеешь о своем поступке, просто начни все заново.
До тех пор, пока ты не наберешь еще один блок, транзакция, которую ты только что совершил, останется в мемпуле. Так что не забудьте смайнить хотя бы 1 дополнительный блок, чтобы получить подтверждение и в своей цепочке.
Конец третьей части
На этом мы завершаем третью часть, в которой мы рассматривали вопрос о программном выполнении транзакции. Сама программа не была сложной, но теперь, когда вы знаете что делать, флаг вам в руки! Может быть, вы хотите создать свой собственный простой бумажник для экспериментов? Вперед! Всегда хотел попробовать, как установить более высокую комиссию за транзакцию с использованием RBF? Теперь ты можешь это выяснить! Ну что ж, если вы уловили ход мысли, что regtest может быть лучшей средой для начала погони за ней!
Некоторая дополнительная помощь.
Погружение во внутренности regtest блокчейна
Одна большая разница между regtest и тестовой\главной сетью в том, что у вас нет причудливого блок эксплорера. Но это не значит, что иногда нужно проверять или подтверждать что-то в regtest блокчейне. Поэтому для этого я использую еще одну программу python3, чтобы получить базовую информацию regtest блокчейне и транзакциях.
Вот программа python3, которую я использовал для создания транзакции (удобно называемая "info.py"):
from bitcoinrpc.authproxy import AuthServiceProxy, JSONRPCException
import sys, simplejson
rpc_connection = AuthServiceProxy("http://%s:%[email protected]:18444"%("bitcoin", "talk"),timeout = 120)
def get_blockchain_size():
iBlockSize = rpc_connection.getblockcount()
return iBlockSize
def get_block_hash(height):
blockhash = rpc_connection.getblockhash(height)
return blockhash
def get_transactions_in_block(blockhash):
return rpc_connection.getblock(blockhash)['tx']
def get_mempool_transactions():
mempoolTransactions = rpc_connection.getrawmempool()
return mempoolTransactions
def lookup_transaction(txid):
blockfound = -1
regTestChainSize = get_blockchain_size()
for i in range(0, regTestChainSize+1):
blockhash = get_block_hash(i)
for transaction in get_transactions_in_block(blockhash):
if transaction == txid:
blockfound = i
return blockfound
def lookup_mempool_transaction(txid):
found = 0
mempoolTransactions = get_mempool_transactions()
if len(mempoolTransactions) > 0:
for transaction in get_mempool_transactions():
if transaction == txid:
found = 1
return found
def getraw_transaction(txid):
return rpc_connection.getrawtransaction(txid)
def decode_transaction(raw):
parsed = rpc_connection.decoderawtransaction(raw)
formatted_json = simplejson.dumps(parsed, indent=4)
#print(json.loads(parsed, indent=4, sort_keys=False))
return formatted_json
#=============
if __name__ == "__main__":
if len(sys.argv) == 1:
operation = 'chain'
else:
operation = sys.argv[1]
#Show info on the entire chain and mempool. This is the default operation if none is specified.
if operation.lower() == 'chain':
regTestChainSize = get_blockchain_size()
print('The network currently consists out of %s blocks.' % regTestChainSize)
if regTestChainSize < 100:
print('Warning: No transactions can be performed on this chain yet since there are no mature blocks!')
for i in range(0, regTestChainSize+1):
print('---------------------------------')
print('Block height: %s' %i)
blockhash = get_block_hash(i)
print('Block hash : %s' % blockhash)
print('Transactions:')
for transaction in get_transactions_in_block(blockhash):
print(transaction)
print('---------------------------------')
print('')
print('Mempool transactions')
print('---------------------------------')
mempoolTransactions = get_mempool_transactions()
if len(mempoolTransactions) > 0:
for transaction in get_mempool_transactions():
print(transaction)
else:
print('Mempool is empty')
#Show info on blocks containing at least one transaction other than coinbase reward
if operation.lower() == 'blocktrans':
regTestChainSize = get_blockchain_size()
print('Scanning for blocks with at least one transaction other than coinbase reward:')
for i in range(0, regTestChainSize+1):
blockhash = get_block_hash(i)
transInBlock = get_transactions_in_block(blockhash)
if len(transInBlock) > 1:
print('---------------------------------')
print('Block height: %s' %i)
print('Block hash : %s' % blockhash)
print('Transactions:')
for transaction in transInBlock:
print(transaction)
print('---------------------------------')
#Show info on blocks containing at least one transaction other than coinbase reward
if operation.lower() == 'mempool':
print('')
print('Mempool transactions:')
mempoolTransactions = get_mempool_transactions()
if len(mempoolTransactions) > 0:
for transaction in get_mempool_transactions():
print(transaction)
else:
print('Mempool is empty')
#Show info on blocks containing at least one transaction other than coinbase reward
if operation.lower() == 'trans':
try:
txid = sys.argv[2]
except:
sys.exit('Provide txid as search value')
print('Looking up transaction %s' % txid)
mempoolfound = lookup_mempool_transaction(txid)
if mempoolfound == 1:
print('')
print('------------------')
print('Transaction is in the mempool (so unconfirmed)')
print('------------------')
else:
blockfound = lookup_transaction(txid)
if blockfound > -1:
print('')
print('------------------')
print('Transaction is included in block with height %s' % blockfound)
print('------------------')
else:
sys.exit('Transaction was not found in any block or mempool.')
raw_transaction = getraw_transaction(txid)
print('------------------')
print('Raw transaction:')
print(raw_transaction)
print('------------------')
decoded_json = decode_transaction(raw_transaction)
print('')
print('------------------')
print('Decoded transaction:')
print(decoded_json)
print('------------------')
Это первая программа, которую можно запустить с помощью параметра запуска для выполнения различных задач. Я представлю их одну за другой:
Получаем информацию о блоках в цепочке и мемпуле.
python3 info.py chain
The network currently consists out of 175 blocks.
---------------------------------
Block height: 1
Block hash : 20e3935462a04eefca66b965d9ff6c3fc75388be010ca890ddb426110160a94d
Transactions:
36d07cbb236db866aaecc768bf514a90bf2c8ae2d3f5ec852cc72f757b741f8d
---------------------------------
---------------------------------
Block height: 175
Block hash : 07c82a7e5ae630408d2f4f99af3dbcaacc2328d50bbea3beb6a8f7cdf55eb8bd
Transactions:
17a4fd218d864633207deedfbb2c943cefd78f96d4df5838fc731e76a4bdb16b
b5b3646b2452775964fde010c0e20282d9cb00e5d8fb3d1a75121f8725edc844
---------------------------------
Mempool transactions
---------------------------------
817e8bfc4797657d4a0e77389d168aa1018dd087a3c93195525fe0414b65956d
6cf0d8eefbc01340d81b6704907c47da13ebeb79251b1a7a155dc57124429804
Запуск информации с аргументом цепочки (или так как по умолчанию без какого-либо параметра) даст вам общую информацию о regtest блокчейне, включая все идентификаторы транзакций в блоке и транзакций в mempool (если таковые имеются).
Подсказка: Если вам нужна эта информация в текстовом файле, вы можете просто перенаправить ее, так что что-то вроде: python3 info.py chain > mychain.text
Список блоков, сгенерированных пользователем
python3 info.py blocktrans
Scanning for blocks with at lease one transaction other than coinbase reward:
---------------------------------
Block height: 151
Block hash : 189c05ca108ff2091cf049483ea5c52e950dc789b45c51c1feaa1db0b8d0115d
Transactions:
68a10da9c0cf52aab47a6a2eb13c9404b42aff6206834e302eb5e3e1eba2fa1a
545cbb46c3a266f7ba2d0f159b5b91d4d28e140f12ab25a7fb6607940ccd511c
c52ca060fa3ac2cbb41b8708f5664a8418518b4c9b10224ee7e60f8e9783a960
002c700a5803ed49e52b3c58494b8a13a2b6d3fbab7be3c67aac2e57e02f0f71
88386302f926dd77e7aff370ddf440321daba1892c5e470de7460668eea645bd
372c3b5dffb323c850677ab852c90308b09b25a6895ee0825fc6fa20ce1dc6cf
---------------------------------
---------------------------------
Block height: 152
Block hash : 6886d26823dab1c57f2aa1c5de27d50648a0da961e8ac5f155500ebe1ea95cb9
Transactions:
2e6f32adedc779c1eb948d77cb870f52a010e7dae703093f65db79cde1c98efa
85479cb7cfd788e94bb4b3007871857051b5282a07a1acfc458a57f9e785d35a
44c76adea68b6dd2785b61a0e48325ffd9cca95fb3e6a24585ee617e150ed99b
c784407fed108736c9a71d9ab2eb22ce1bf46c1ec9006d75e8a28671af86d1ae
---------------------------------
---------------------------------
Block height: 153
Block hash : 71dfd97a6aca1e4183b1579fe3333aadc21670c2cf2cef88ff3281b3b8b6e111
Transactions:
dbb52d7049c9339a81b66e90509238b51d73571ff5b296d1a62d8beafb071389
499b9284eede4f80e4e19e8f1f2db289447cf85ff90bb2b536f1c8bc66ba9a99
---------------------------------
---------------------------------
Block height: 166
Block hash : 5ab0a67ca9d6457193f57059cd37982b6620f6da016176177822f8519351f04a
Transactions:
1523e59493e6a64981256a546060ca41c40a2d51c7985c6637704918a00fcf2f
d88cf4d784d475cda43f72262573ef4c89fdf418e0a3afff2013ed917471209f
---------------------------------
---------------------------------
Block height: 170
Block hash : 1484a88ee17b4dbc610969af1e9f6624fabd3871ccc911f0363e3a3c113757c7
Transactions:
12a00e59825ed735c7d7f9e6429bd78f4b445fe0898118b5676e7190a6475508
9e664ee1f641212df8ee6078f3f6f68bfeb2e920902d8362c2471c9081366f73
---------------------------------
---------------------------------
Block height: 175
Block hash : 07c82a7e5ae630408d2f4f99af3dbcaacc2328d50bbea3beb6a8f7cdf55eb8bd
Transactions:
17a4fd218d864633207deedfbb2c943cefd78f96d4df5838fc731e76a4bdb16b
b5b3646b2452775964fde010c0e20282d9cb00e5d8fb3d1a75121f8725edc844
Особенно, когда вы экспериментируете с транзакциями, вы можете потерять те блоки, которые содержат ваши собственные генерируемые транзакции, а не только coinbase транзакции. Таким образом, при использовании параметра "blocktrans" вы можете получить список всех блоков, содержащих более 1 транзакции.
Список всех транзакций в мемпуле
python3 info.py mempool
Mempool transactions:
817e8bfc4797657d4a0e77389d168aa1018dd087a3c93195525fe0414b65956d
6cf0d8eefbc01340d81b6704907c47da13ebeb79251b1a7a155dc57124429804
Довольно просто, когда вы используете аргумент mempool, вы получите все txid (если таковые имеются) в данный момент в мемпуле.
Получение подробной информации о транзакции
python3 info.py trans 817e8bfc4797657d4a0e77389d168aa1018dd087a3c93195525fe0414b65956d
Looking up transaction 817e8bfc4797657d4a0e77389d168aa1018dd087a3c93195525fe0414b65956d
------------------
Transaction is in the mempool (so unconfirmed)
------------------
------------------
Raw transaction:
020000000001011431a62376437bf7228db991c2fdcdf4757750eb8fcbf8e47665841082aaac750000000000ffffffff014094052a010000001976a91462e907b15cbf27d5425399ebf6f0fb50ebb88f1888ac0247304402204d645f8fc2193fee73f835e1987f694e2761f60a6e692b88e340bdcc2c5c4962022058fedeca7be2d22028a6dbac41589bb61e70518a407b48685ec30cf2dbb52c77012102d836add3dce8aeaa481aa2843e6c317654b6cebe36c22f72641ea44a506e245700000000
------------------
------------------
Decoded transaction:
{
"txid": "817e8bfc4797657d4a0e77389d168aa1018dd087a3c93195525fe0414b65956d",
"hash": "22ea77afe16191bc6bba5b02e62de164a2d1c70c0eda65d8e7c055c3f38c8870",
"version": 2,
"size": 194,
"vsize": 113,
"weight": 449,
"locktime": 0,
"vin": [
{
"txid": "75acaa8210846576e4f8cb8feb507775f4cdfdc291b98d22f77b437623a63114",
"vout": 0,
"scriptSig": {
"asm": "",
"hex": ""
},
"txinwitness": [
"304402204d645f8fc2193fee73f835e1987f694e2761f60a6e692b88e340bdcc2c5c4962022058fedeca7be2d22028a6dbac41589bb61e70518a407b48685ec30cf2dbb52c7701",
"02d836add3dce8aeaa481aa2843e6c317654b6cebe36c22f72641ea44a506e2457"
],
"sequence": 4294967295
}
],
"vout": [
{
"value": 49.99976000,
"n": 0,
"scriptPubKey": {
"asm": "OP_DUP OP_HASH160 62e907b15cbf27d5425399ebf6f0fb50ebb88f18 OP_EQUALVERIFY OP_CHECKSIG",
"hex": "76a91462e907b15cbf27d5425399ebf6f0fb50ebb88f1888ac",
"reqSigs": 1,
"type": "pubkeyhash",
"addresses": [
"mpXwg4jMtRhuSpVq4xS3HFHmCmWp9NyGKt"
]
}
}
]
}
------------------
Если вам нужна подробная информация о транзакции, включенная в блок или в мемпуле, вы можете использовать аргумент транзакции вместе с txid. Если транзакция найдена, то будет показана подробная информация.
Заключительные слова
Я надеюсь, что этот гайд дал вам хорошее представление о том, что такое regtest и почему он может пригодиться. Особенно, когда вы хотите поэкспериментировать с транзакциями, скриптами, это может быть лучшим местом, чем тестнет!