Из обоснования дизайна :
Одним из недостатков парадигмы учетной записи является то, что для предотвращения атак воспроизведения каждая транзакция должна иметь «одноразовый номер», чтобы учетная запись отслеживала используемые одноразовые номера и принимала транзакцию только в том случае, если ее одноразовый номер равен 1 после последнего используемого одноразового номера.
На этом сайте было несколько вопросов о слишком низком одноразовом числе транзакций. Что происходит, когда одноразовый номер транзакции слишком велик?
Резюме
From:
адресом с неупорядоченными одноразовыми номерами.From:
адресом с неупорядоченными одноразовыми номерами, например:
Подробности ниже.
Что происходит, когда одноразовый номер транзакции слишком мал?
Я создал две новые учетные записи в своей частной сети --dev, используя
geth -datadir ./data --dev account new
Your new account is locked with a password. Please give a password. Do not forget this password.
Passphrase:
Repeat Passphrase:
Address: {c18f2996c11ba48c7e14233710e5a8580c4fb9ee}
geth -datadir ./data --dev account new
Your new account is locked with a password. Please give a password. Do not forget this password.
Passphrase:
Repeat Passphrase:
Address: {e1fb110faa8850b4c6be5bdb3b7940d1ede87dfb}
Я запустил экземпляр geth для майнинга в отдельном окне, поэтому на первую учетную запись (coinbase) пополняется больше средств по мере добычи новых блоков.
geth --datadir ./data --dev --mine --minerthreads 1 console
В моем главном окне я запустил экземпляр geth, подключенный к экземпляру майнинга.
geth --datadir ./data --dev attach
Я отправляю свою первую транзакцию с моей первой учетной записи на мою вторую учетную запись
> eth.sendTransaction({from: eth.accounts[0], to: eth.accounts[1], value: web3.toWei(1, "ether")})
Unlock account c18f2996c11ba48c7e14233710e5a8580c4fb9ee
Passphrase:
"0xd17510a4c9880155b0237cac58423e05b61ad3f2d5ee90f72d3db2b7d4ea2d47"
Вот детали транзакции для первой транзакции. Для этой транзакции автоматически выделяется одноразовый номер 0.
> eth.getTransaction("0xd17510a4c9880155b0237cac58423e05b61ad3f2d5ee90f72d3db2b7d4ea2d47")
{
blockHash: "0x519ddf8c3d1a094933d2975bb7c9cdf3680c9d66b880ba22b26627f70d90bb54",
blockNumber: 88,
from: "0xc18f2996c11ba48c7e14233710e5a8580c4fb9ee",
gas: 90000,
gasPrice: 20000000000,
hash: "0xd17510a4c9880155b0237cac58423e05b61ad3f2d5ee90f72d3db2b7d4ea2d47",
input: "0x",
nonce: 0,
to: "0xe1fb110faa8850b4c6be5bdb3b7940d1ede87dfb",
transactionIndex: 0,
value: 1000000000000000000
}
Я отправляю вторую транзакцию из моей первой учетной записи в мою вторую учетную запись, указав одноразовый номер 0, и получаю ожидаемый результат «Слишком низкий одноразовый номер».
> eth.sendTransaction({from: eth.accounts[0], to: eth.accounts[1], value: web3.toWei(1, "ether"), nonce:0})
Nonce too low
at InvalidResponse (<anonymous>:-81662:-106)
at send (<anonymous>:-156322:-106)
at sendTransaction (<anonymous>:-133322:-106)
at <anonymous>:1:1
Что происходит, когда одноразовый номер транзакции слишком высок?
Теперь я отправляю третью транзакцию из моей первой учетной записи во вторую учетную запись, указав одноразовый номер 10000, и получаю обратно хэш транзакции, подтверждающий, что транзакция была отправлена в пул транзакций.
> eth.sendTransaction({from: eth.accounts[0], to: eth.accounts[1], value: web3.toWei(1, "ether"), nonce:10000})
"0x5b09270d6bcd33297527a1f6b08fa1528deec01e82a100c7e62ee93fbdcd1f7d"
В окне майнинга появится сообщение о том, что транзакция получена. Однако транзакция никогда не добывается.
I0409 15:25:07.699859 10726 worker.go:569] commit new work on block 95 with 0 txs & 0 uncles. Took 289.587µs
I0409 15:25:08.493883 10726 xeth.go:1028] Tx(0x5b09270d6bcd33297527a1f6b08fa1528deec01e82a100c7e62ee93fbdcd1f7d) to: 0xe1fb110faa8850b4c6be5bdb3b7940d1ede87dfb
> I0409 15:26:13.472919 10726 worker.go:348] 🔨 Mined block (#95 / 7fe1ada0). Wait 5 blocks for confirmation
I0409 15:26:13.473634 10726 worker.go:569] commit new work on block 96 with 0 txs & 0 uncles. Took 630.605µs
I0409 15:26:13.473707 10726 worker.go:447] 🔨 🔗 Mined 5 blocks back: block #90
I0409 15:26:13.474252 10726 worker.go:569] commit new work on block 96 with 0 txs & 0 uncles. Took 447.451µs
I0409 15:26:18.921404 10726 worker.go:348] 🔨 Mined block (#96 / 760e117c). Wait 5 blocks for confirmation
I0409 15:26:18.922033 10726 worker.go:569] commit new work on block 97 with 0 txs & 0 uncles. Took 547.204µs
I0409 15:26:18.922096 10726 worker.go:447] 🔨 🔗 Mined 5 blocks back: block #91
Я пытаюсь получить детали транзакции для моих третьих транзакций. blockHash и blockNumber всегда остаются нулевыми.
> eth.getTransaction("0x5b09270d6bcd33297527a1f6b08fa1528deec01e82a100c7e62ee93fbdcd1f7d")
{
blockHash: null,
blockNumber: null,
from: "0xc18f2996c11ba48c7e14233710e5a8580c4fb9ee",
gas: 90000,
gasPrice: 20000000000,
hash: "0x5b09270d6bcd33297527a1f6b08fa1528deec01e82a100c7e62ee93fbdcd1f7d",
input: "0x",
nonce: 10000,
to: "0xe1fb110faa8850b4c6be5bdb3b7940d1ede87dfb",
transactionIndex: null,
value: 1000000000000000000
}
Я проверяю состояние пула транзакций и предполагаю, что транзакция с одноразовым номером 10000 находится в очереди.
> txpool.status
{
pending: 0,
queued: 1
}
Я пытаюсь отправить четвертую транзакцию с одноразовым номером 1. Транзакция заминирована.
> eth.sendTransaction({from: eth.accounts[0], to: eth.accounts[1], value: web3.toWei(1, "ether"), nonce:1})
"0x545af0a0276e154a8669921373de8904a330b829318a7c83f5bd9f9771e71ff8"
> eth.getTransaction("0x545af0a0276e154a8669921373de8904a330b829318a7c83f5bd9f9771e71ff8")
{
blockHash: "0xc125f5da96e36ac87728a35eae8ff8046bcc08c6242825daa4b6bb1e7b460a01",
blockNumber: 101,
from: "0xc18f2996c11ba48c7e14233710e5a8580c4fb9ee",
gas: 90000,
gasPrice: 20000000000,
hash: "0x545af0a0276e154a8669921373de8904a330b829318a7c83f5bd9f9771e71ff8",
input: "0x",
nonce: 1,
to: "0xe1fb110faa8850b4c6be5bdb3b7940d1ede87dfb",
transactionIndex: 0,
value: 1000000000000000000
}
Поэтому я пытаюсь отправить пятую транзакцию с одноразовым номером 3 (теперь есть пробел, поскольку последний действительный одноразовый номер равен 1). Транзакция попадает в очередь пула транзакций и не добывается.
> eth.sendTransaction({from: eth.accounts[0], to: eth.accounts[1], value: web3.toWei(1, "ether"), nonce:3})
"0x895ec329c3a1d53acf7a429721025f2ff01d5558feee0595daa0fa9c0282d461"
> eth.getTransaction("0x895ec329c3a1d53acf7a429721025f2ff01d5558feee0595daa0fa9c0282d461")
{
blockHash: null,
blockNumber: null,
from: "0xc18f2996c11ba48c7e14233710e5a8580c4fb9ee",
gas: 90000,
gasPrice: 20000000000,
hash: "0x895ec329c3a1d53acf7a429721025f2ff01d5558feee0595daa0fa9c0282d461",
input: "0x",
nonce: 3,
to: "0xe1fb110faa8850b4c6be5bdb3b7940d1ede87dfb",
transactionIndex: null,
value: 1000000000000000000
}
Я отправляю шестую транзакцию с одноразовым номером 2 (это заполняет пробел между последним допустимым одноразовым номером 1 и транзакцией в очереди с одноразовым номером 3).
> eth.sendTransaction({from: eth.accounts[0], to: eth.accounts[1], value: web3.toWei(1, "ether"), nonce:2})
"0xea7a6350d6f7aa61a5f515452021de905917338d3b4d354e19fc53d8bd4982f4"
Обе транзакции с одноразовыми номерами 2 и 3 теперь добываются.
> eth.getTransaction("0xea7a6350d6f7aa61a5f515452021de905917338d3b4d354e19fc53d8bd4982f4")
{
blockHash: "0xabcfea8140fdbe3d04bab05cb0232a8c73de4a6bc2307907ede9d45ad58d7107",
blockNumber: 170,
from: "0xc18f2996c11ba48c7e14233710e5a8580c4fb9ee",
gas: 90000,
gasPrice: 20000000000,
hash: "0xea7a6350d6f7aa61a5f515452021de905917338d3b4d354e19fc53d8bd4982f4",
input: "0x",
nonce: 2,
to: "0xe1fb110faa8850b4c6be5bdb3b7940d1ede87dfb",
transactionIndex: 0,
value: 1000000000000000000
}
> eth.getTransaction("0x895ec329c3a1d53acf7a429721025f2ff01d5558feee0595daa0fa9c0282d461")
{
blockHash: "0xabcfea8140fdbe3d04bab05cb0232a8c73de4a6bc2307907ede9d45ad58d7107",
blockNumber: 170,
from: "0xc18f2996c11ba48c7e14233710e5a8580c4fb9ee",
gas: 90000,
gasPrice: 20000000000,
hash: "0x895ec329c3a1d53acf7a429721025f2ff01d5558feee0595daa0fa9c0282d461",
input: "0x",
nonce: 3,
to: "0xe1fb110faa8850b4c6be5bdb3b7940d1ede87dfb",
transactionIndex: 1,
value: 1000000000000000000
}
Я проверяю состояние пула транзакций, и транзакция с одноразовым номером 10000 все еще находится в очереди и останется навсегда.
> txpool.status
{
pending: 0,
queued: 1
}
Я выключил свой экземпляр geth для майнинга и подключенный экземпляр geth и перезапустил их оба. Теперь я проверяю статус пула транзакций, и транзакция с одноразовым номером 10000 исчезла.
> txpool.status
{
pending: 0,
queued: 0
}
Исходный код пула транзакций
Глядя на core/tx_pool.go (#48-50) , максимальный размер очереди составляет 64 транзакции для транзакций с неупорядоченной последовательностью одноразовых номеров на адрес отправителя.
const (
maxQueued = 64 // max limit of queued txs per address
)
А core/tx_pool.go (#436-456) показывает код, удаляющий транзакции, если очередь переполнена:
for i, entry := range promote {
// If we reached a gap in the nonces, enforce transaction limit and stop
if entry.Nonce() > guessedNonce {
if len(promote)-i > maxQueued {
if glog.V(logger.Debug) {
glog.Infof("Queued tx limit exceeded for %s. Tx %s removed\n", common.PP(address[:]), common.PP(entry.hash[:]))
}
for _, drop := range promote[i+maxQueued:] {
delete(txs, drop.hash)
}
}
break
}
// Otherwise promote the transaction and move the guess nonce if needed
pool.addTx(entry.hash, address, entry.Transaction)
delete(txs, entry.hash)
if entry.Nonce() == guessedNonce {
guessedNonce++
}
}
Краш-тестирование Geth со слишком высоким одноразовым номером
sudo swapoff -a
в Linux) и запустив другие программы, занимающие много памяти.если вы используете каску + метамаску и видите это после перезапуска узла, попробуйте сбросить свою учетную запись в метамаске: «Настройки»> «Дополнительно»> «Сбросить учетную запись».
Что происходит, когда одноразовый номер транзакции слишком велик?
Транзакция с "слишком высоким" одноразовым значением может быть добавлена в tx_pool и пройти проверку на первом этапе, но она не пройдет проверку на втором этапе во время выполнения перехода состояния.
Он строго следовал Обоснованию дизайна: «принимает транзакцию только в том случае, если ее одноразовый номер равен 1 после последнего использованного одноразового номера».
go-ethereum/core/state_transition.go
func (self *StateTransition) preCheck() (err error) {
msg := self.msg
sender := self.from()
// Make sure this transaction's nonce is correct
if msg.CheckNonce() {
if n := self.state.GetNonce(sender.Address()); n != msg.Nonce() {
return NonceError(msg.Nonce(), n)
}
}
// Pre-pay gas
if err = self.buyGas(); err != nil {
if IsGasLimitErr(err) {
return err
}
return InvalidTxError(err)
}
return nil
}
В обмене Blockchain.info, использующем переводы с изменением формы между двумя криптовалютами, например, эфириум в биткойн, это сообщение появляется, если статус вашей первой транзакции все еще находится на рассмотрении.
Это защита от двойных транзакций. Подождите, пока первая транзакция не будет завершена, прежде чем пытаться сдвинуть больше.
тайвано
конфиденциальностьisahumanright.eth
q9f
конфиденциальностьisahumanright.eth
Томас Клоуз
альпер
конфиденциальностьisahumanright.eth
swapoff -a
отключает файл подкачки, так что моя эффективная память составляет всего 4 ГБ.судо
Роберт Ошлер
Ашвани Агарвал