A Transaction.Fork is a Transaction recorded in a non-consensus block, such an uncle.pull/802/head
parent
4b140c87df
commit
818f84a424
@ -0,0 +1,63 @@ |
||||
defmodule Explorer.Chain.Transaction.Fork do |
||||
@moduledoc """ |
||||
A transaction fork has the same `hash` as a `t:Explorer.Chain.Transaction.t/0`, but associates that `hash` with a |
||||
non-consensus uncle `t:Explorer.Chain.Block.t/0` instead of the consensus block linked in the |
||||
`t:Explorer.Chain.Transaction.t/0` `block_hash`. |
||||
""" |
||||
|
||||
use Explorer.Schema |
||||
|
||||
alias Explorer.Chain.{Block, Hash, Transaction} |
||||
|
||||
@optional_attrs ~w()a |
||||
@required_attrs ~w(hash index uncle_hash)a |
||||
@allowed_attrs @optional_attrs ++ @required_attrs |
||||
|
||||
@typedoc """ |
||||
* `hash` - hash of contents of this transaction |
||||
* `index` - index of this transaction in `uncle`. |
||||
* `transaction` - the data shared between all forks and the consensus transaction. |
||||
* `uncle` - the block in which this transaction was mined/validated. |
||||
* `uncle_hash` - `uncle` foreign key. |
||||
""" |
||||
@type t :: %__MODULE__{ |
||||
hash: Hash.t(), |
||||
index: Transaction.transaction_index(), |
||||
transaction: %Ecto.Association.NotLoaded{} | Transaction.t(), |
||||
uncle: %Ecto.Association.NotLoaded{} | Block.t(), |
||||
uncle_hash: Hash.t() |
||||
} |
||||
|
||||
@primary_key false |
||||
schema "transaction_forks" do |
||||
field(:index, :integer) |
||||
|
||||
timestamps() |
||||
|
||||
belongs_to(:transaction, Transaction, foreign_key: :hash, references: :hash, type: Hash.Full) |
||||
belongs_to(:uncle, Block, foreign_key: :uncle_hash, references: :hash, type: Hash.Full) |
||||
end |
||||
|
||||
@doc """ |
||||
All fields are required for transaction fork |
||||
|
||||
iex> changeset = Fork.changeset( |
||||
...> %Fork{}, |
||||
...> %{ |
||||
...> hash: "0x3a3eb134e6792ce9403ea4188e5e79693de9e4c94e499db132be086400da79e6", |
||||
...> index: 1, |
||||
...> uncle_hash: "0xe52d77084cab13a4e724162bcd8c6028e5ecfaa04d091ee476e96b9958ed6b48" |
||||
...> } |
||||
...> ) |
||||
iex> changeset.valid? |
||||
true |
||||
|
||||
""" |
||||
def changeset(%__MODULE__{} = fork, attrs \\ %{}) do |
||||
fork |
||||
|> cast(attrs, @allowed_attrs) |
||||
|> validate_required(@required_attrs) |
||||
|> assoc_constraint(:transaction) |
||||
|> assoc_constraint(:uncle) |
||||
end |
||||
end |
@ -0,0 +1,16 @@ |
||||
defmodule Explorer.Repo.Migrations.CreateTransactionBlockUncles do |
||||
use Ecto.Migration |
||||
|
||||
def change do |
||||
create table(:transaction_forks, primary_key: false) do |
||||
add(:hash, references(:transactions, column: :hash, on_delete: :delete_all, type: :bytea), null: false) |
||||
add(:index, :integer, null: false) |
||||
add(:uncle_hash, references(:blocks, column: :hash, on_delete: :delete_all, type: :bytea), null: false) |
||||
|
||||
timestamps() |
||||
end |
||||
|
||||
create(index(:transaction_forks, :uncle_hash)) |
||||
create(unique_index(:transaction_forks, [:uncle_hash, :index])) |
||||
end |
||||
end |
@ -0,0 +1,23 @@ |
||||
defmodule Explorer.Chain.Transaction.ForkTest do |
||||
use Explorer.DataCase |
||||
|
||||
alias Ecto.Changeset |
||||
alias Explorer.Chain.Transaction.Fork |
||||
|
||||
doctest Fork |
||||
|
||||
test "a transaction fork cannot be inserted if the corresponding transaction does not exist" do |
||||
assert %Changeset{valid?: true} = changeset = Fork.changeset(%Fork{}, params_for(:transaction_fork)) |
||||
|
||||
assert {:error, %Changeset{errors: [transaction: {"does not exist", []}]}} = Repo.insert(changeset) |
||||
end |
||||
|
||||
test "a transaction fork cannot be inserted if the corresponding uncle does not exist" do |
||||
transaction = insert(:transaction) |
||||
|
||||
assert %Changeset{valid?: true} = |
||||
changeset = Fork.changeset(%Fork{}, %{hash: transaction.hash, index: 0, uncle_hash: block_hash()}) |
||||
|
||||
assert {:error, %Changeset{errors: [uncle: {"does not exist", []}]}} = Repo.insert(changeset) |
||||
end |
||||
end |
Loading…
Reference in new issue