forked from chaintope/glueby
/
timestamp.rb
102 lines (88 loc) · 3.25 KB
/
timestamp.rb
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
module Glueby
module Contract
# Timestamp feature allows users to send transaction with op_return output which has sha256 hash of arbitary data.
# Timestamp transaction has
# * 1 or more inputs enough to afford transaction fee.
# * 1 output which has op_return, application specific prefix, and sha256 hash of data.
# * 1 output to send the change TPC back to the wallet.
#
# Storing timestamp transaction to the blockchain enables everyone to verify that the data existed at that time and a user signed it.
class Timestamp
include Glueby::Contract::TxBuilder
autoload :Syncer, 'glueby/contract/timestamp/syncer'
module Util
include Glueby::Internal::Wallet::TapyrusCoreWalletAdapter::Util
module_function
def create_tx(wallet, prefix, data, fee_estimator)
tx = Tapyrus::Tx.new
tx.outputs << Tapyrus::TxOut.new(value: 0, script_pubkey: create_script(prefix, data))
fee = fee_estimator.fee(dummy_tx(tx))
sum, outputs = wallet.internal_wallet.collect_uncolored_outputs(fee)
fill_input(tx, outputs)
fill_change_tpc(tx, wallet, sum - fee)
wallet.internal_wallet.sign_tx(tx)
end
def create_payload(prefix, data)
payload = +''
payload << prefix
payload << data
payload
end
def create_script(prefix, data)
script = Tapyrus::Script.new
script << Tapyrus::Script::OP_RETURN
script << create_payload(prefix, data)
script
end
def get_transaction(tx)
Glueby::Internal::RPC.client.getrawtransaction(tx.txid, 1)
end
end
include Glueby::Contract::Timestamp::Util
attr_reader :tx, :txid
# @param [String] content Data to be hashed and stored in blockchain.
# @param [String] prefix prefix of op_return data
# @param [Glueby::Contract::FeeEstimator] fee_estimator
# @param [Symbol] digest type which select of:
# - :sha256
# - :double_sha256
# - :none
# @raise [Glueby::Contract::Errors::UnsupportedDigestType] if digest unsupport
def initialize(
wallet:,
content:,
prefix: '',
fee_estimator: Glueby::Contract::FixedFeeEstimator.new,
digest: :sha256
)
@wallet = wallet
@content = content
@prefix = prefix
@fee_estimator = fee_estimator
@digest = digest
end
# broadcast to Tapyrus Core
# @return [String] txid
# @raise [TxAlreadyBroadcasted] if tx has been broadcasted.
# @raise [InsufficientFunds] if result of listunspent is not enough to pay the specified amount
def save!
raise Glueby::Contract::Errors::TxAlreadyBroadcasted if @txid
@tx = create_tx(@wallet, @prefix, digest_content, @fee_estimator)
@txid = @wallet.internal_wallet.broadcast(@tx)
end
private
def digest_content
case @digest&.downcase
when :sha256
Tapyrus.sha256(@content)
when :double_sha256
Tapyrus.double_sha256(@content)
when :none
@content
else
raise Glueby::Contract::Errors::UnsupportedDigestType
end
end
end
end
end