Skip to content

Commit

Permalink
Add YAML continuation command implementation
Browse files Browse the repository at this point in the history
Co-authored-by: David Roldán <Odraxs@users.noreply.github.com>
  • Loading branch information
EdwinGuayacan and Odraxs committed Jan 31, 2023
1 parent 5482acb commit e95e92d
Show file tree
Hide file tree
Showing 12 changed files with 297 additions and 23 deletions.
105 changes: 105 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -445,6 +445,10 @@ alias Kadena.Pact.ExecCommand

### Building a Continuation Command

There are two ways to create a ContCommand.

#### Using [attributes](#attributes) structures

```elixir
alias Kadena.Cryptography
alias Kadena.Pact
Expand Down Expand Up @@ -508,6 +512,107 @@ rollback = true
}}
```

#### With a `YAML` file

YAML struct:

- `networkId`: [NetworkID](#networkid) value.
- `data`: there are two ways to set the data from the `YAML` file:
- `data`: [EnvData](#envdata) value.
- `dataFile`: The name of a `json` file in the same directory as the `YAML` file.
- `nonce`: [Nonce](#nonce) value.
- `publicMeta`: [Metadata](#metadata) value.
- `keyPairs`: [KeyPairs](#keypairs) values.
- `signers`: [Signers](#signers) values.
- `pactTxHash`: [PactTxHash](#pacttxhash-continuation-command) value.
- `rollback`: [Rollback](#rollback-continuation-command) value.
- `Step`: [Step](#step-continuation-command) value.
- `proof`: [Proof](#proof-continuation-command) value.


The scheme below shows how to set the different values of a `ContCommand`

```YAML
networkId:
data/dataFile:
nonce:
publicMeta:
creationTime:
chainId:
gasLimit:
gasPrice:
ttl:
sender:
keyPairs:
- public:
secret:
signers:
- publicKey:
scheme:
addr:
capsList:
- name:
args:
-
pactTxHash:
step:
rollback:
proof:

```
**Example**

YAML file:
```YAML
networkId: :testnet04
data:
accounts_admin_keyset:
- 6ffea3fabe4e7fe6a89f88fc6d662c764ed1359fbc03a28afdac3935415347d7
nonce: 2023-01-01 00:00:00.000000 UTC
publicMeta:
creationTime: 1667249173
chainId: "0"
gasLimit: 2500
gasPrice: 0.01
ttl: 28800
sender: k:6ffea3fabe4e7fe6a89f88fc6d662c764ed1359fbc03a28afdac3935415347d7
keyPairs:
- public: 6ffea3fabe4e7fe6a89f88fc6d662c764ed1359fbc03a28afdac3935415347d7
secret: 99f7e1e8f2f334ae8374aa28bebdb997271a0e0a5e92c80be9609684a3d6f0d4
capsList:
name: coin.GAS
args:
- 6ffea3fabe4e7fe6a89f88fc6d662c764ed1359fbc03a28afdac3935415347d7
pactTxHash: yxM0umrtdcvSUZDc_GSjwadH6ELYFCjOqI59Jzqapi4
step: 1
rollback: true

```

```elixir
alias Kadena.Pact.ContCommand

"~/your_file_path"
|> ContCommand.from_yaml()
|> ContCommand.build()

{:ok,
%Kadena.Types.Command{
cmd:
"{\"meta\":{\"chainId\":\"0\",\"creationTime\":1667249173,\"gasLimit\":2500,\"gasPrice\":0.01,\"sender\":\"k:6ffea3fabe4e7fe6a89f88fc6d662c764ed1359fbc03a28afdac3935415347d7\",\"ttl\":28800},\"networkId\":\"testnet04\",\"nonce\":\"2023-01-01 00:00:00.000000 UTC\",\"payload\":{\"cont\":{\"data\":{\"accounts_admin_keyset\":[\"6ffea3fabe4e7fe6a89f88fc6d662c764ed1359fbc03a28afdac3935415347d7\"]},\"pactId\":\"\",\"proof\":null,\"rollback\":true,\"step\":0}},\"signers\":[{\"addr\":null,\"clist\":[{\"args\":[\"6ffea3fabe4e7fe6a89f88fc6d662c764ed1359fbc03a28afdac3935415347d7\"],\"name\":\"coin.GAS\"}],\"pubKey\":\"6ffea3fabe4e7fe6a89f88fc6d662c764ed1359fbc03a28afdac3935415347d7\",\"scheme\":\"ED25519\"}]}",
hash: %Kadena.Types.PactTransactionHash{
hash: "psIXOGGneMAV1Ie3zx5O1VWMFueFZrShvaBx4YOCkjQ"
},
sigs: [
%Kadena.Types.Signature{
sig:
"1ae6e796bbf8e1ddb005945508ac6fd13cc6435c4f63609cff299114865fd13879b8b5bcad13383ae377acc10411e49e745397320a2ba5bf9d1370cafbf90a06"
}
]
}}

```

## Chainweb Pact API

Interaction with [Chainweb Pact API][chainweb_pact_api_doc] is done through the [**Kadena.Chainweb.Pact**][chainweb_pact_api] module using simple functions to access endpoints.
Expand Down
75 changes: 73 additions & 2 deletions lib/pact/command/cont_command.ex
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ defmodule Kadena.Pact.ContCommand do

alias Kadena.Chainweb.Pact.CommandPayload
alias Kadena.Cryptography.{Sign, Utils}
alias Kadena.Pact.Command.Hash
alias Kadena.Pact.Command.{Hash, YamlReader}

alias Kadena.Types.{
Command,
Expand Down Expand Up @@ -103,7 +103,34 @@ defmodule Kadena.Pact.ContCommand do
def new(_opts), do: %__MODULE__{}

@impl true
def from_yaml(_path), do: new()
def from_yaml(path) when is_binary(path) do
with {:ok, map_result} <- YamlReader.read(path) do
network_id = Map.get(map_result, "networkId")
data = Map.get(map_result, "data")
nonce = Map.get(map_result, "nonce", "")
meta_data = Map.get(map_result, "publicMeta", MetaData.new())
pact_tx_hash = Map.get(map_result, "pactTxHash", "")
step = Map.get(map_result, "step", 0)
proof = Map.get(map_result, "proof")
rollback = Map.get(map_result, "rollback", true)
keypairs = Map.get(map_result, "keyPairs", [])
signers = Map.get(map_result, "signers", [])

%__MODULE__{}
|> process_metadata(meta_data)
|> process_keypairs(keypairs)
|> process_signers(signers)
|> set_network(network_id)
|> set_data(data)
|> set_nonce(nonce)
|> set_pact_tx_hash(pact_tx_hash)
|> set_proof(proof)
|> set_step(step)
|> set_rollback(rollback)
end
end

def from_yaml(_path), do: {:error, [path: :invalid]}

@impl true
def set_network(%__MODULE__{} = cmd_request, network) do
Expand Down Expand Up @@ -313,4 +340,48 @@ defmodule Kadena.Pact.ContCommand do

defp build_signatures([%SignCommand{sig: sig} | rest], result),
do: build_signatures(rest, result ++ [Signature.new(sig)])

defp process_metadata(%__MODULE__{} = cmd_request, %MetaData{} = metadata),
do: set_metadata(cmd_request, metadata)

defp process_metadata(%__MODULE__{} = cmd_request, %{} = metadata) do
case MetaData.new(metadata) do
%MetaData{} = result -> %{cmd_request | meta_data: result}
{:error, reason} -> {:error, [meta_data: :invalid] ++ reason}
end
end

defp process_metadata(%__MODULE__{}, _metadata), do: {:error, [metadata: :invalid]}

defp process_keypairs(%__MODULE__{} = cmd_request, [%{} = keypair_data | rest]) do
case KeyPair.new(keypair_data) do
%KeyPair{} = result ->
cmd_request
|> add_keypair(result)
|> process_keypairs(rest)

{:error, reason} ->
{:error, [keypair: :invalid] ++ reason}
end
end

defp process_keypairs(%__MODULE__{} = cmd_request, []), do: cmd_request
defp process_keypairs(%__MODULE__{}, _keypair), do: {:error, [keypair: :invalid]}
defp process_keypairs({:error, reason}, _keypairs), do: {:error, reason}

defp process_signers(%__MODULE__{} = cmd_request, [%{} = signers_data | rest]) do
case Signer.new(signers_data) do
%Signer{} = result ->
cmd_request
|> add_signer(result)
|> process_signers(rest)

{:error, reason} ->
{:error, [signers: :invalid] ++ reason}
end
end

defp process_signers(%__MODULE__{} = cmd_request, []), do: cmd_request
defp process_signers({:error, reason}, _signers), do: {:error, reason}
defp process_signers(%__MODULE__{}, _signers), do: {:error, [signers: :invalid]}
end
100 changes: 86 additions & 14 deletions test/pact/command/cont_command_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -20,26 +20,98 @@ defmodule Kadena.Pact.ContCommandTest do

describe "create ContCommand with YAMl file" do
setup do
path = ""
path = "test/support/yaml_tests_files/for_test_cont.yaml"
path2 = "test/support/yaml_tests_files/for_test_commands_1.yaml"
path3 = "test/support/yaml_tests_files/for_test_commands_2.yaml"
path4 = "test/support/yaml_tests_files/for_test_commands_3.yaml"
path5 = "test/support/yaml_tests_files/for_test_commands_4.yaml"
path6 = "test/support/yaml_tests_files/for_test_commands_5.yaml"
path7 = "test/support/yaml_tests_files/for_test_commands_6.yaml"
path8 = "test/support/yaml_tests_files/for_test_commands_7.yaml"
bad_path = "test/support/yaml_tests_files/no_existent.yaml"

%{
path: path
path: path,
path2: path2,
path3: path3,
path4: path4,
path5: path5,
path6: path6,
path7: path7,
path8: path8,
bad_path: bad_path
}
end

test "with a valid YAML file", %{path: path} do
%Kadena.Pact.ContCommand{
data: nil,
keypairs: [],
meta_data: nil,
network_id: nil,
nonce: nil,
pact_tx_hash: nil,
proof: nil,
rollback: nil,
signers: [],
step: nil
} = ContCommand.from_yaml(path)
{:ok,
%Kadena.Types.Command{
cmd:
"{\"meta\":{\"chainId\":\"0\",\"creationTime\":1667249173,\"gasLimit\":1000,\"gasPrice\":1.0e-6,\"sender\":\"k:554754f48b16df24b552f6832dda090642ed9658559fef9f3ee1bb4637ea7c94\",\"ttl\":28800},\"networkId\":\"testnet04\",\"nonce\":\"2023-06-13 17:45:18.211131 UTC\",\"payload\":{\"cont\":{\"data\":{\"accounts-admin-keyset\":[\"6ffea3fabe4e7fe6a89f88fc6d662c764ed1359fbc03a28afdac3935415347d7\"]},\"pactId\":\"yxM0umrtdcvSUZDc_GSjwadH6ELYFCjOqI59Jzqapi4\",\"proof\":null,\"rollback\":true,\"step\":1}},\"signers\":[{\"addr\":null,\"clist\":[],\"pubKey\":\"6ffea3fabe4e7fe6a89f88fc6d662c764ed1359fbc03a28afdac3935415347d7\",\"scheme\":\"ED25519\"},{\"addr\":\"cc30ae980161eba5da95a0d27dbdef29f185a23406942059c16cb120f6dc9dea\",\"clist\":[{\"args\":[\"8693e641ae2bbe9ea802c736f42027b03f86afe63cae315e7169c9c496c17332\"],\"name\":\"coin.GAS\"}],\"pubKey\":\"cc30ae980161eba5da95a0d27dbdef29f185a23406942059c16cb120f6dc9dea\",\"scheme\":\"ED25519\"}]}",
hash: %Kadena.Types.PactTransactionHash{
hash: "fcR4cObX0BegUNvQu3CeMn8FhMlufY6CYHxQa39eJuY"
},
sigs: [
%Kadena.Types.Signature{
sig:
"eef27b61796cd1668e73078af4de4cb028796291c99e54a12be5f98ba0121b4bb631b322fdd583458e5ae30d962039452676a3f3c83a1f3b4b1be2e74b188a0d"
}
]
}} =
path
|> ContCommand.from_yaml()
|> ContCommand.build()
end

test "without metadata, signers and keypairs", %{path2: path2} do
{:ok,
%Kadena.Types.Command{
cmd:
"{\"meta\":{\"chainId\":\"0\",\"creationTime\":0,\"gasLimit\":0,\"gasPrice\":0,\"sender\":\"\",\"ttl\":0},\"networkId\":\"testnet04\",\"nonce\":\"step01\",\"payload\":{\"cont\":{\"data\":{\"accounts-admin-keyset\":[\"ba54b224d1924dd98403f5c751abdd10de6cd81b0121800bf7bdbdcfaec7388d\"]},\"pactId\":\"\",\"proof\":null,\"rollback\":true,\"step\":0}},\"signers\":[]}",
hash: %Kadena.Types.PactTransactionHash{
hash: "njHWk39wmyfWDKFF5GJRRlfBcdj57oTUZYKiKY3Ru4I"
},
sigs: []
}} =
path2
|> ContCommand.from_yaml()
|> ContCommand.build()
end

test "with an invalid path" do
{:error, [path: :invalid]} = ContCommand.from_yaml(123)
end

test "with a non existing YAML file", %{bad_path: bad_path} do
{:error,
%YamlElixir.FileNotFoundError{
message:
"Failed to open file \"test/support/yaml_tests_files/no_existent.yaml\": no such file or directory"
}} = ContCommand.from_yaml(bad_path)
end

test "with an invalid meta_data", %{path3: path3} do
{:error, [metadata: :invalid]} = ContCommand.from_yaml(path3)
end

test "with an invalid meta_data args", %{path4: path4} do
{:error, [meta_data: :invalid, gas_price: :invalid]} = ContCommand.from_yaml(path4)
end

test "with an invalid keypair", %{path5: path5} do
{:error, [keypair: :invalid]} = ContCommand.from_yaml(path5)
end

test "with an invalid keypair args", %{path6: path6} do
{:error, [keypair: :invalid, pub_key: :invalid]} = ContCommand.from_yaml(path6)
end

test "with an invalid signers", %{path7: path7} do
{:error, [signers: :invalid]} = ContCommand.from_yaml(path7)
end

test "with an invalid signers args", %{path8: path8} do
{:error, [signers: :invalid, scheme: :invalid]} = ContCommand.from_yaml(path8)
end
end

Expand Down
14 changes: 7 additions & 7 deletions test/pact/command/exec_command_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,13 @@ defmodule Kadena.Pact.ExecCommandTest do
describe "create ExecCommand with YAMl file" do
setup do
path = "test/support/yaml_tests_files/for_test_exec.yaml"
path2 = "test/support/yaml_tests_files/for_test_exec_2.yaml"
path3 = "test/support/yaml_tests_files/for_test_exec_3.yaml"
path4 = "test/support/yaml_tests_files/for_test_exec_4.yaml"
path5 = "test/support/yaml_tests_files/for_test_exec_5.yaml"
path6 = "test/support/yaml_tests_files/for_test_exec_6.yaml"
path7 = "test/support/yaml_tests_files/for_test_exec_7.yaml"
path8 = "test/support/yaml_tests_files/for_test_exec_8.yaml"
path2 = "test/support/yaml_tests_files/for_test_commands_1.yaml"
path3 = "test/support/yaml_tests_files/for_test_commands_2.yaml"
path4 = "test/support/yaml_tests_files/for_test_commands_3.yaml"
path5 = "test/support/yaml_tests_files/for_test_commands_4.yaml"
path6 = "test/support/yaml_tests_files/for_test_commands_5.yaml"
path7 = "test/support/yaml_tests_files/for_test_commands_6.yaml"
path8 = "test/support/yaml_tests_files/for_test_commands_7.yaml"
bad_path = "test/support/yaml_tests_files/no_existent.yaml"

%{
Expand Down
26 changes: 26 additions & 0 deletions test/support/yaml_tests_files/for_test_cont.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
networkId: :testnet04
data:
accounts-admin-keyset:
- 6ffea3fabe4e7fe6a89f88fc6d662c764ed1359fbc03a28afdac3935415347d7
nonce: 2023-06-13 17:45:18.211131 UTC
publicMeta:
creationTime: 1667249173
chainId: "0"
gasLimit: 1000
gasPrice: 0.000001
ttl: 28800
sender: k:554754f48b16df24b552f6832dda090642ed9658559fef9f3ee1bb4637ea7c94
keyPairs:
- public: 6ffea3fabe4e7fe6a89f88fc6d662c764ed1359fbc03a28afdac3935415347d7
secret: 99f7e1e8f2f334ae8374aa28bebdb997271a0e0a5e92c80be9609684a3d6f0d4
signers:
- publicKey: cc30ae980161eba5da95a0d27dbdef29f185a23406942059c16cb120f6dc9dea
scheme: :ed25519
addr: cc30ae980161eba5da95a0d27dbdef29f185a23406942059c16cb120f6dc9dea
capsList:
- name: coin.GAS
args:
- 8693e641ae2bbe9ea802c736f42027b03f86afe63cae315e7169c9c496c17332
pactTxHash: yxM0umrtdcvSUZDc_GSjwadH6ELYFCjOqI59Jzqapi4
step: 1
rollback: true

0 comments on commit e95e92d

Please sign in to comment.