Ethereum Transaction Lifecycle

How Transaction Lifecycle Works

Transaction State

An ethereum transaction progresses through a series of states, starting with the unknown state, until it is in block

Unknown: A transaction that has not been seen nor processed by the network would be in the unknown state.

Pending: A transaction is in the pending state when it is waiting to be picked and processed by miners. They are in the so-called mempool. Miners usually select transactions with higher gas prices first, so transactions with lower gas prices may remain in the pending state for long periods. Transactions with the lowest gas prices may never get picked up, which would result in them getting “stuck” in the pending state indefinitely.

In Block: A transaction moves to the in block state when a miner has successfully selected the transaction and mined it within a block. Once in block, a transaction may move back to the pending state if the block is forked.

Replaced: A transaction can move to the replaced state from the pending state when either of these events occur:

  • Another transaction originating from the same sender with the same nonce enters the in block state, or
  • Another transaction originating from the same sender with the same nonce with a 12% higher gas price enters the pending state

State Transitions

As shown in the diagram above, the transitions between states also have names:

Pooled: A transaction in the unknown state that enters the pool of transactions waiting to be selected by miners is said to be pooled and enters the pending state. It is also possible that a transaction in replaced state becomes pooled again, if the conditions for its replacement are no longer true (ex: in the rare case where a transaction with low gas price that was in block gets forked, and the replaced transaction with same nonce+sender with higher gas price was still floating around).

Mined: A mined transaction is one that has been processed by a miner, creating a block. Once mined, a transaction is said to be in the in block state. Due to the peer-to-peer nature of the Ethereum network, from the perspective of a given node a transaction can move from the unknown state directly to the in block state without visibly passing through the pending state. For the same reason, from the perspective of a given node a transaction may also pass from the replaced state to the in block state without passing through the pending state.

Replaced: A transaction that moves from the pending state to the replaced state is said to be replaced. As described above, this occurs when:

  • Another transaction originating from the same sender with the same nonce enters the in block state, or
  • Another transaction originating from the same sender with the same nonce with a 12% higher gas price enters the pending state

Forked: A forked transaction occurs when a mined transaction (i.e a transaction that is in the in block state) is part of a block that gets reversed by the network. All transactions within the reversed block will subsequently be forked thus moving them from the in block state to the pending state.

Confirmed: A transaction in the in block state is confirmed every time a subsequent, child block gets mined.

How Transaction Lifecycle Is Used:

With GraphQL you can subscribe to transitions of a specific ethereum transaction in real-time. Furthermore, you have the ability to define precisely the data you want per transition.

Subscriptions

Stream all transition for transaction 0x3be3b44ae48a074d3b79e3054bb3b62b5c5e5a8fc2210cd1dc7c7932ae5addcd in real-time. Do not be scared we will breakdown the query

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112

subscription {
    transactionLifecycle(hash: "0x3be3b44ae48a074d3b79e3054bb3b62b5c5e5a8fc2210cd1dc7c7932ae5addcd"){
        previousState
        currentState
        transitionName
        transition {
            __typename

            ... on TrxTransitionInit {
                transaction {
                    ...TransactionFragment
                }
                blockHeader {
                    ...BlockHeaderFragment
                }
                trace {
                    ...TransactionTraceFragment
                }
                confirmations
                replacedById
            }

            ...on TrxTransitionPooled {
                transaction {
                    ...TransactionFragment
                }
            }

            ...on TrxTransitionMined {
                blockHeader {
                    ...BlockHeaderFragment
                }
                trace {
                    ...TransactionTraceFragment
                }
                confirmationsher
            }

            ...on TrxTransitionForked {
                transaction {
                    ...TransactionFragment
                }
            }

            ...on TrxTransitionConfirmed {
                confirmations
            }

            ...on TrxTransitionReplaced {
                replacedById
            }

        }
    }
}

fragment TransactionFragment on Transaction {
    hash
    from
    to
    nonce
    gasPrice
    gasLimit
    value
    inputData
    signature {
        v
        s
        r
    }
}

fragment TransactionTraceFragment on TransactionTrace {
    hash
    from
    to
    nonce
    gasPrice
    gasLimit
    value
    inputData
    signature {
        v
        s
        r
    }
    cumulativeGasUsed
    publicKey
    index
    create
    outcome
}

fragment BlockHeaderFragment on BlockHeader {
    parentHash
    unclesHash
    coinbase
    stateRoot
    transactionsRoot
    receiptRoot
    logsBloom
    difficulty
    number
    gasLimit
    gasUsed
    timestamp
    extraData
    mixHash
    nonce
    hash
}

Breaking down the Graphql Query

Filtering the query

We filter our query by specifying a hash in the transactionLifecycle subscription connection:

1
2
3
4

subscription {
    transactionLifecycle(hash: "0x3be3b44ae48a074d3b79e3054bb3b62b5c5e5a8fc2210cd1dc7c7932ae5addcd"){
        previousState

Specifying Fields

Next we specify the fields we want the subscription to return. In this example we are returning previousState, currentState and transition.

1
2
3
4
5
6

subscription {
    transactionLifecycle(hash: "0x3be3b44ae48a074d3b79e3054bb3b62b5c5e5a8fc2210cd1dc7c7932ae5addcd"){
        previousState
        currentState
        transitionName

transition is defined as a Union type in Graphql. This means that transition can be one of six different types:

  • TrxTransitionInit: This transition is the first one you will receive everytime you initiate a transaction subscription. It can be used to initialize your system.
  • TrxTransitionPooled: This transition will be sent when the transaction has first been seen in our memory pool.
  • TrxTransitionMined: This transition occurs when the transaction has been mined in a block.
  • TrxTransitionForked: This transition occurs when the transaction has been forked.
  • TrxTransitionConfirmed: This transition will occur every time the mined transaction’s block has a new child block.
  • TrxTransitionReplaced: This transition occurs when another transaction replaces the transaction.

Each of these fields have specific attributes that you can choose to display

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

subscription{
  transactionLifecycle(hash: "0x3be3b44ae48a074d3b79e3054bb3b62b5c5e5a8fc2210cd1dc7c7932ae5addcd"){
    previousState
    currentState
    transitionName
    transition {
      __typename

    ... on TrxTransitionInit {
        // insert desired TrxTransitionInit attributes
    }

    ...on TrxTransitionPooled {
        // insert desired TrxTransitionReceived attributes
    }

    ...on TrxTransitionMined {
      // insert desired TrxTransitionMined attributes
    }

    ...on TrxTransitionForked {
        // insert desired TrxTransitionForked attributes
    }

    ...on TrxTransitionConfirmed {
        // insert desired TrxTransitionConfirmed attributes
    }

    ...on TrxTransitionReplaced {
        // insert desired TrxTransitionReplaced attributes
    }
  }
}

Some of the attributes have a same attribute, for example TrxTransitionInit, TrxTransitionPooled and TrxTransitionForked all have a transaction attribute. Instead of repeating the attribute’ struct 3 times we can create a fragment that will be used by all 3 transition types

1
2
3
4
5
6

            ...on TrxTransitionForked {
                transaction {
                    ...TransactionFragment
                }
            }

the fragment can de defined like this:


fragment TransactionFragment on Transaction {
    hash
    from
    to
    nonce
    gasPrice
    gasLimit
    value
    inputData
    signature {
        v
        s
        r
    }

Putting all this together we get the full query we started with.