Class: AppChain::TransactionSigner

Inherits:
Object
  • Object
show all
Defined in:
lib/appchain/transaction_signer.rb

Class Method Summary collapse

Class Method Details

.decode(tx_content) ⇒ Hash

decode and parse bytes to hex string

Parameters:

  • tx_content (String)

    hex string

Returns:

  • (Hash)


104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/appchain/transaction_signer.rb', line 104

def decode(tx_content)
  data = original_decode(tx_content)
  utx = data[:unverified_transaction]
  tx = utx[:transaction]
  version = tx[:version]

  tx[:value] = Utils.from_bytes(tx[:value])
  tx[:data] = Utils.from_bytes(tx[:data])
  tx[:nonce] = Utils.add_prefix_for_not_blank(tx[:nonce])
  utx[:signature] = Utils.from_bytes(utx[:signature])

  if version == 0 # rubocop:disable Style/NumericPredicate
    tx.delete(:to_v1)
    tx.delete(:chain_id_v1)
    tx[:to] = Utils.add_prefix_for_not_blank(tx[:to])
  elsif version == 1
    tx[:to] = Utils.from_bytes(tx[:to])
    tx[:chain_id] = Utils.from_bytes(tx[:chain_id])
  end

  data
end

.encode(transaction, private_key) ⇒ Object

sign transaction

Parameters:



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
# File 'lib/appchain/transaction_signer.rb', line 13

def encode(transaction, private_key)
  tx = AppChain::Protos::Transaction.new

  to = AppChain::Utils.remove_hex_prefix(transaction.to)&.downcase

  tx.nonce = transaction.nonce
  tx.quota = transaction.quota
  tx.data = AppChain::Utils.to_bytes(transaction.data)
  tx.value = hex_to_bytes(transaction.value)
  tx.version = transaction.version
  tx.valid_until_block = transaction.valid_until_block

  if transaction.version.zero?
    tx.to = to unless to.nil?
    tx.chain_id = transaction.chain_id
  elsif transaction.version == 1
    tx.to_v1 = Utils.to_bytes(to) unless to.nil?
    tx.chain_id_v1 = hex_to_bytes(transaction.chain_id)
  end

  encoded_tx = Protos::Transaction.encode(tx)

  private_key_bytes = AppChain::Utils.to_bytes(private_key)

  protobuf_hash = Utils.keccak256(encoded_tx)

  signature = Ciri::Crypto.ecdsa_signature(private_key_bytes, protobuf_hash).signature

  unverified_tx = Protos::UnverifiedTransaction.new(transaction: tx, signature: signature)

  encoded_unverified_tx = Protos::UnverifiedTransaction.encode(unverified_tx)

  AppChain::Utils.from_bytes(encoded_unverified_tx)
end

.original_decode(tx_content) ⇒ Hash

decode and support forks

Parameters:

  • tx_content (String)

    hex string

Returns:

  • (Hash)


81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/appchain/transaction_signer.rb', line 81

def original_decode(tx_content)
  data = simple_decode(tx_content)
  utx = data[:unverified_transaction]
  tx = utx[:transaction]
  version = tx[:version]

  if version == 0 # rubocop:disable Style/NumericPredicate
    tx.delete(:to_v1)
    tx.delete(:chain_id_v1)
  elsif version == 1
    tx[:to] = tx.delete(:to_v1)
    tx[:chain_id] = tx.delete(:chain_id_v1)
  else
    raise Transaction::VersionError, "transaction version error, expected 0 or 1, got #{version}"
  end

  data
end

.simple_decode(tx_content) ⇒ Object

unsign transaction

Parameters:

  • tx_content (String)

    hex string



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
# File 'lib/appchain/transaction_signer.rb', line 51

def simple_decode(tx_content)
  content_bytes = AppChain::Utils.to_bytes(tx_content)
  unverified_transaction = Protos::UnverifiedTransaction.decode(content_bytes)

  signature = unverified_transaction["signature"]

  transaction = unverified_transaction["transaction"]
  msg = Protos::Transaction.encode(transaction)
  msg_hash = AppChain::Utils.keccak256(msg)
  pubkey = Ciri::Crypto.ecdsa_recover(msg_hash, signature)
  pubkey_hex = Utils.from_bytes(pubkey[1..-1])

  from_address = Utils.keccak256(pubkey[1..-1])[-20..-1]
  from_address_hex = Utils.from_bytes(from_address)

  sender = {
    address: from_address_hex,
    public_key: pubkey_hex
  }

  {
    unverified_transaction: unverified_transaction.to_h,
    sender: sender
  }
end