Внутренние транзакции: что это такое?
1 мин. чтения
Это немного проще понять, зная, что у каждого кошелька есть два адреса. Первый адрес — это “внешний” или публичный адрес, с которым знакомы большинство людей (0x..), а второй адрес можно считать “внутренним”. Все действия в блокчейне Ethereum начинаются с использования внешних адресов для выполнения какого-либо действия, а внутренние адреса используются за кадром со смарт-контрактами для выполнения небольших функций. Каждый раз, когда смарт-контракту нужно отправить ETH или самостоятельно выполнить какое-то техническое действие, он вызывает функцию, изначально называвшуюся “сообщением”, и которая в конечном итоге была переименована во “внутреннюю транзакцию”.
Это название не соответствует действительности, потому что внутренние транзакции фактически не являются транзакциями, поскольку они не включены напрямую в блокчейн. Вместо этого они больше похожи на побочный продукт функциональности смарт-контракта. Однако, важно помнить, внутренние транзакции все таки отображаются в общем балансе кошелька. Их обычно можно найти на вкладке ‘Internal Transaction’ (“Внутренняя транзакция”) в Etherscan.io
Отмена или замена транзакции после её отправки
Ошибка: Недостаточно ETH для отправки
Не появились ETH или токены ERC20, отправленные на биржу или с нее
Ошибка: Адрес не проверен суммированием
Как отправить транзакцию с MEW web
Есть ли у MEW минимальные требования для отправки?
Моя транзакция не «прошла». Почему с меня списали средства?
Что такое Nonce-число?
Внутренние транзакции: что это такое?
Внутренние транзакции: что это такое?
1 мин. чтения
Это немного проще понять, зная, что у каждого кошелька есть два адреса. Первый адрес — это “внешний” или публичный адрес, с которым знакомы большинство людей (0x..), а второй адрес можно считать “внутренним”. Все действия в блокчейне Ethereum начинаются с использования внешних адресов для выполнения какого-либо действия, а внутренние адреса используются за кадром со смарт-контрактами для выполнения небольших функций. Каждый раз, когда смарт-контракту нужно отправить ETH или самостоятельно выполнить какое-то техническое действие, он вызывает функцию, изначально называвшуюся “сообщением”, и которая в конечном итоге была переименована во “внутреннюю транзакцию”.
Normal transactions VS. Internal transactions in etherscan
There are two types of transactions mentioned under No Of Transactions:
Normal transactions and Internal transactions.
What is the difference between them and why are the Normal transactions usually much less than Internal transactions?
4 Answers 4
Internal transactions, despite the name (which isn’t part of the yellowpaper; it’s a convention people have settled on) aren’t actual transactions, and aren’t included directly in the blockchain; they’re value transfers that were initiated by executing a contract.
Check these answers as well
In the Ethereum protocol there’s only transactions and message calls. A transaction is a type of message call.
A transaction may perform other message calls, but these are not transactions (even though blockchain explorers may label them inaccurately as «internal transactions»). These (internal) message calls are not published on the blockchain.
This is what you will see on the blockchain: a «Normal transaction». An «Internal Transaction» is the effects of taking the data part, feeding it to the contract C1, and executing the Ethereum Virtual Machine. The data is what tells C1 that it should call another contract C2: there is no separate
Contracts calling each other, along with receiving payment, is the reason why «Normal transactions are usually much less than Internal transactions». For example, TheDAO tokens were originally purchased by calling a function on TheDAO and sending ETH with it.
Инкапсуляция для настоящих самураев, или нюансы, связанные с ключевым словом internal в C#
Пролог: internal is new public
Каждый из нас мечтал о проекте, где всё будет сделано правильно. Это кажется вполне естественным. Как только ты узнаёшь о самой возможности писать хороший код, как только слышишь легенды о том самом коде, который можно легко читать и изменять, сразу загораешься тем самым «ну вот теперь я точно всё сделаю правильно, я ведь теперь умный и Макконнела читал».
Случился такой проект и в моей жизни. Очередной. Причём делаю я его под добровольным надзором, где за каждой моей строчкой следят. Соответственно, уже не только хотелось, но и надо было делать всё правильно. Одним из «правильно» было «чти инкапсуляцию и закрывайся по максимуму, потому что открыться всегда успеешь, а закрыться обратно потом будет поздно». И поэтому я везде, где только мог, стал использовать для классов модификатор доступа internal вместо public. И, естественно, когда ты начинаешь активно использовать новую для тебя фичу языка, возникают некоторые нюансы. О них по порядку и хочу рассказать.
Исключительно для того, чтобы напомнить и обозначить.
Юнит-тесты и дружественные сборки
В C++ была такая странноватая фича, как friendly classes. Классы можно было назначить друзьями, и тогда граница инкапсуляции между ними стиралась. Подозреваю, что это не самая странная фича в C++. Возможно, даже в десятку самых странных не входит. Но выстрелить себе в ногу, связав несколько классов намертво, как-то слишком уж легко, а подходящий случай под эту фичу придумать очень тяжело.
А потом в том же проекте я начал познавать одну из ветвей пути настоящего самурая: юнит-тестирование. А по фэн-шую юнит-тесты должны лежать в отдельной сборке. По тому же фэн-шую всё, что можно спрятать внутри сборки, нужно спрятать внутри сборки. Я встал перед весьма и весьма неприятным выбором. Или тесты будут лежать рядышком и уходить клиенту вместе с полезным для него кодом, или всё покроется ключевым словом public, как долго лежавший в сырости хлебушек.
И вот тут откуда-то из закромов моей памяти было добыто что-то про дружественные сборки. Оказалось, что если у вас есть сборка «YourAssemblyName», то можно написать вот так:
И сборка «YourAssemblyName.Tests» будет видеть то, что помечено ключевым словом internal в «YourAssemblyName». Строчку эту можно вписать, чуть что, в AssemblyInfo.cs, который VS создаёт специально для хранения таких атрибутов.
Таким образом, волки остаются сыты, овцы целы, всё, что можно, по-прежнему прячется внутри сборки, юнит тесты живут в отдельной сборке, как и положено, а фича, про которую я едва вспомнил, обретает повод её использовать. Возможно, единственный существующий повод.
Чуть не забыл один важный момент. Действия атрибута InternalsVisibleTo одностороннее.
protected protected. Чтобы понять суть претензий компилятора, давайте вспомним, какие ограничения накладывают internal и protected. internal — только внутри сборки. protected — только наследники. Заметьте, любые наследники. А если класс B пометить как public, то в другой сборке можно определить его наследников. И тогда акссесор set действительно получит доступ туда, куда его не имеет всё свойство. Так как компилятор C# параноидален, он даже возможности такой допустить не может.
Спасибо ему за это, но нам нужно дать наследникам доступ к аксессору. И специально для таких случаев есть модификатор доступа protected internal.
Так что если мы хотим, чтобы компилятор позволил нам пользоваться этим свойством и задавать его в наследниках, нужно сделать так:
А правильная иерархия модификаторов доступа выглядит приблизительно так:
Интерфейсы
Итак, ситуация: A, I, B сидели на трубе.
Сидели ровно и за пределы сборки не совались. Но были забракованы компилятором. Тут суть претензий ясна из сообщения об ошибке. Реализация интерфейса должна быть открытой. Даже если сам интерфейс закрыт. Было бы логично привязать доступ реализации интерфейса к его доступности, но чего нет, того нет. Реализация интерфейса должна быть public.
Обратите внимание, что во втором случае нет модификатора доступа. Кому в таком случае доступна реализация метода? Скажем так, никому. Проще показать на примере:
Явная реализация интерфейса I означает, что пока мы явно не приведём переменную к типу I, методов реализующий этот интерфейс не существует. Каждый раз писать (b as I).SomeMethod() может быть излишней нагрузкой. Как и ((I)b).SomeMethod(). И я нашёл два способа это дело обойти. До одного додумался сам, а второй честно нагуглил.
Способ первый — фабрика:
Ну, или любой другой паттерн, который позволит вам спрятать этот нюанс.
Способ второй — методы расширения:
Что удивительно, это срабатывает. Эти строки перестают выдавать ошибку:
Ведь обращение идёт, как нам подсказывает IntelliSense в Visual Studio, не к методам явной реализации интерфейса, а к методам расширения. А к ним обращаться никто не запрещает. И методы расширения интерфейса можно вызывать на всех его реализациях.
Но остаётся один нюанс. Внутри самого класса нужно обращаться к этому методу через ключевое слово this, иначе компилятор не поймёт, что мы хотим обратиться к методу расширения:
И так, и так, у нас или public, там где его быть не должно, но там он, кажется, вреда не причиняет, или немножко лишнего кода на каждый internal-интерфейс. Выберите меньшее зло себе по вкусу.
Рефлексия
Я об это больно стукнулся, когда попытался найти через рефлексию конструктор, который, естественно, был помечен, как internal, у internal-класса. И оказалось, что рефлексия не выдаст ничего, что не было бы public. И это, в принципе, логично.
Во-первых, рефлексия, если я правильно помню то, что писали умные люди в умных книгах, это про поиск информации в метаданных сборки. Которые, по идее, не должны выдавать лишнего (я так думал, по крайней мере). Во-вторых, основное применение рефлексии — сделать вашу программу расширяемой. Вы предоставляете посторонним какой-то интерфейс (возможно, даже в виде интерфейсов, фить-ха!). А они его реализуют и предоставляют плагины, моды, расширения в виде загружаемой на ходу сборки, из которой рефлексия их и достаёт. И само собой, ваше API будет public. То есть, смотреть на internal через рефлексию невозможно технически и бессмысленно с практической точки зрения.
Update. Тут в комментариях выяснилось, что рефлексия позволяет, если её явно попросить об этом, отрефлексировать вообще всё. Будь оно хоть internal, хоть private. Если вы не пишете какой-то инструмент для анализа кода, старайтесь так не делать, пожалуйста. Текст дальше всё ещё актуален для случаев, когда мы ищем открытые типы членов. И вообще, не проходите мимо комментариев, там много чего интересного.
На этом можно было бы и закончить с рефлексией, но давайте вернёмся к предыдущему примеру, где A, I, B сидели на трубе:
Автор класса A решил, что ничего страшного не случится, если метод internal-класса пометить как public, чтобы компилятор не ныл, и чтобы не пришлось городить ещё кода. Интерфейс отмечен, как internal, класс, его реализующий, отмечен как internal, снаружи до метода, помеченного как public, вроде бы никак не добраться.
И тут открывает дверь и тихонько крадётся рефлексия:
Изучите этот код, вбейте его в студию, если вам так хочется. Тут мы пытаемся с помощью рефлексии найти все методы из всех типов нашей трубы (namespace Pipe). И вот какие результаты нам это даёт:
In type I we found Void SomeMethod()
NULL! Can’t find method SomeMethod in type IExtensions
In type A we found Void SomeMethod()
NULL! Can’t find method OtherMethod in type A
NULL! Can’t find method SomeMethod in type B
NULL! Can’t find method OtherMethod in type B
Сразу скажу, что используя объект типа MethodInfo, найденный метод можно вызвать. То есть, если рефлексия что-то нашла, то нарушить инкапсуляцию чисто теоретически можно. И у нас кое-что найдено. Во-первых, тот самый public void SomeMethod() из класса A. Это было ожидаемо, что тут ещё сказать. У этой поблажки всё-таки могут быть последствия. Во-вторых, void SomeMethod() из интерфейса I. Это уже интереснее. Как бы мы не запирались, но абстрактные методы, размещённые в интерфейсе (или что на самом деле там размещает CLR) на самом деле являются открытыми. Отсюда вывод, вынесенный в отдельный абзац:
Смотрите внимательно кому и какие объекты типа System.Type вы отдаёте.
Но тут ещё один нюанс с этими двумя найденными методами, который я хотел бы рассмотреть. Методы internal-интерфейсов и открытые методы internal-классов можно найти с помощью рефлексии. Как человек разумный, я сделаю вывод, что они попадают в метаданные. Как человек опытный, я этот вывод проверю. И в этом нам поможет ILDasm.
Сборка была собрана в режипрме Release
TypeDef #2 (02000003)
——————————————————-
TypDefName: Pipe.I (02000003)
Flags : [NotPublic] [AutoLayout] [Interface] [Abstract] [AnsiClass] (000000a0)
Extends : 01000000 [TypeRef]
Method #1 (06000004)
——————————————————-
MethodName: SomeMethod (06000004)
Flags : [Public] [Virtual] [HideBySig] [NewSlot] [Abstract] (000005c6)
RVA : 0x00000000
ImplFlags : [IL] [Managed] (00000000)
CallCnvntn: [DEFAULT]
hasThis
ReturnType: Void
No arguments.
Беглый осмотр показывает, что в метаданные попадает всё, как бы оно ни было помечено. Рефлексия ещё заботливо от нас прячет то, что посторонним видеть не положено. Так что вполне может быть, что лишние пять строк кода на каждый метод internal-интерфейса не такое уж и большое зло. Тем не менее, главный вывод остаётся прежним:
Смотрите внимательно кому и какие объекты типа System.Type вы отдаёте.
Но это уже, конечно, следующий уровень, после воцарения ключевого слова internal во всех местах, где нет необходимости в public.
Знаете, что самое классное в использовании ключевого слова internal везде внутри сборки? Когда она разрастётся, вам придётся её поделить на две и больше. А в процессе вам придётся взять паузу на то, чтобы сделать некоторые типы открытыми. И вам придётся задуматься о том, какие именно типы достойны того, чтобы стать открытыми. Хотя бы мельком.
Это означает следующее: эта практика написания кода заставит вас ещё раз задуматься о том, какую форму примет архитектурная граница между новорожденными сборками. Что может прекраснее?
Начиная с версии C# 7.2 появился новый модификатор доступа private protected. И я пока понятия не имею, что это такое, и с чем его едят. Так как не сталкивался на практике. Но буду рад узнать в комментариях. Но не копипаст из документации, а реальные случаи, когда этот модификатор доступа может понадобится.
Understanding an Ethereum Transaction
A transaction is the act of transferring Ethereum-based assets from one address to another that is initiated from your wallet (What is a wallet?). The exact steps may vary from one platform to the other, but they generally follow a similar process as shown in our tutorial here.
Types of Transaction
Before we get to know how a transaction works, there are basically three types of transactions that you can perform on the Ethereum blockchain.
— Normal Transaction:
A transaction where an EOA (Externally Owned Address, or typically referred to as a wallet address) sends ETH directly to another EOA. When viewing an address on Etherscan, this type of transaction will be shown under the Transaction tab. Click here for a sample transaction.
— Internal Transaction:
This refers to a transfer of ETH that is carried out through a smart contract as an intermediary. When viewing an address on Etherscan, this type of transaction will be shown under the Internal Txns tab. Click here for a sample transaction.
— Token Transfer:
Transactions of ERC-20 or ERC-721 tokens are labelled as Token Transfer transactions. When viewing an address on Etherscan, this type of transaction will be shown under either the Erc20 Token Txns or Erc721 Token Txns tab, depending on the respective token type. Click here for a sample transaction.
The Life Cycle of a Transaction
A transaction is created when a user initiates through their wallet a transfer of assets from their wallet address to another wallet or contract address.
Once a transaction is created, a transaction hash (also known as Transaction ID or txhash) is assigned to this transaction. This acts as a reference number for the parties involved in the transaction. You can use this to look up the transaction and find out its status and details on block explorers such as Etherscan.
After the transaction is created, it is broadcasted to the network into a pool with other transactions. From here, miners pick out transactions to be included into a block on the blockchain. This process is usually what determines how long a transaction will take.
During this process, there are two factors that ultimately determine the time taken for your transaction to be verified: the network traffic and your transaction’s gas fee (What is Gas Fee?).
i. Network Traffic:
On paper, the current Ethereum network is capable of processing an average of 15 transactions per second. If your transaction is taking much longer than usual to be confirmed or the recommended gas fee is higher than normal, then chances are that the traffic is congested.
ii. Gas Fee:
When the traffic gets congested, miners would often prioritize transactions with higher gas fees. This leaves those with lower gas fees to be stuck with a pending status. Etherscan has a feature that calculates and proposes a recommended gas price for a transaction depending on the network traffic and the average gas price. This feature is called the Gas Tracker and is accessible here.
Once your transaction has been picked up and verified by a miner, the transaction is then considered successful and complete. The status on its Etherscan Transaction Details page will now read «Success» and you can expect to see your new ETH/token balance updated on your wallet soon.
But wait! There is still another factor to be aware of when expecting an incoming transaction, and that is the block confirmation number. A block confirmation number denotes the number of blocks in the blockchain that have been processed (or mined) since the block that your transaction was included in was processed. For example, a transaction with a 5 block confirmation number means that five blocks have been confirmed since the block that the transaction is in was processed.
Different wallet/exchange platforms require different minimum block confirmation numbers (for example, Binance requires a minimum of 12 block confirmation number) and so the waiting time for an asset to be reflected on a wallet or an exchange may vary. Please refer to your service provider for more information on this.
If your transaction is not successful, please refer to our article here to understand the reasons it failed and what to do next.
If your transaction is stuck in pending status, please refer to our article here on how to cancel/replace the said transaction.
Ethereum Gas Tracker ⛽
Low
10 mins: 0 secs
Average
3 mins: 0 secs
High
Estimated Cost of Transfers & Interactions:
| Low | Average | High |
|---|---|---|
| $20.28 | $20.55 | $21.10 |
| $62.41 | $63.25 | $64.91 |
| $54.61 | $55.34 | $56.80 |
Top 50 Gas Guzzlers (Contracts / Accounts that consume a lot of Gas)
| Rank | Address | Fees Last 3hrs | % Used 3hrs | Fees Last 24hrs | % Used 24hrs | Analytics |
|---|---|---|---|---|---|---|
| 🥇 1 | $318,009.67 (76.43 Eth) | 9.70% |
Top 50 Gas Spenders (Sending Accounts that pay a lot of Gas)
| Rank | Address | Fees Last 3hrs | % Spent 3hrs | Fees Last 24hrs | % Spent 24hrs | Analytics |
|---|
Historical Data For Gas Oracle Prices
Gas fee refers to the fee required to successfully conduct a transaction on the Ethereum blockchain. Gas fees are paid in Ethereum’s native currency Ether (ETH) and denominated in gwei. Learn more about Gas in our Knowledge Base.



Low
Average
High


