Skip to content

Commit 13eb8e1

Browse files
committed
add testnet
1 parent 8ff7617 commit 13eb8e1

13 files changed

Lines changed: 198 additions & 100 deletions

ex/config/runtime.exs

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ config :ama, :snapshot_height, (System.get_env("SNAPSHOT_HEIGHT") || "34076355")
1919

2020
#Bind Interaces
2121
config :ama, :offline, (!!System.get_env("OFFLINE") || nil)
22+
config :ama, :testnet, (!!System.get_env("TESTNET") || nil)
2223

2324
config :ama, :http_ipv4, ((System.get_env("HTTP_IPV4") || "0.0.0.0") |> :unicode.characters_to_list() |> :inet.parse_ipv4_address() |> (case do {:ok, addr}-> addr end))
2425
config :ama, :http_port, (System.get_env("HTTP_PORT") || "80") |> :erlang.binary_to_integer()
@@ -35,21 +36,33 @@ if !Util.verify_time_sync() do
3536
end
3637

3738
path = Path.join([work_folder, "sk"])
38-
if !File.exists?(path) do
39-
#IO.puts "No trainer sk (BLS12-381) in #{path} as base58"
39+
path_seeds = Path.join([work_folder, "seeds"])
40+
if File.exists?(path) do
41+
!File.exists?(path_seeds) && File.copy!(path, path_seeds)
42+
end
43+
if !File.exists?(path_seeds) do
4044
sk = :crypto.strong_rand_bytes(64)
41-
#pk = BlsEx.get_public_key!(sk)
42-
#IO.puts "generated random sk, your pk is #{Base58.encode(pk)}"
4345
:ok = File.write!(path, Base58.encode(sk))
4446
end
45-
sk = File.read!(path) |> String.trim() |> Base58.decode()
46-
pk = BlsEx.get_public_key!(sk)
47-
pop = BlsEx.sign!(sk, pk, BLS12AggSig.dst_pop())
47+
keys = File.read!(path) |> String.split("\n") |> Enum.filter(& &1 != "") |> Enum.map(& String.trim(&1) |> Base58.decode()) |> Enum.map(fn(seed)->
48+
pk = BlsEx.get_public_key!(seed)
49+
pop = BlsEx.sign!(seed, pk, BLS12AggSig.dst_pop())
50+
%{pk: pk, seed: seed, pop: pop}
51+
end)
52+
keys_by_pk = Enum.into(keys, %{}, fn(key)->
53+
{key.pk, %{pop: key.pop, seed: key.seed}}
54+
end)
55+
config :ama, :keys, keys
56+
config :ama, :keys_by_pk, keys_by_pk
57+
58+
first_key = hd(keys)
59+
config :ama, :trainer_pk, first_key.pk
60+
config :ama, :trainer_sk, first_key.seed
61+
config :ama, :trainer_pop, first_key.pop
62+
63+
#for local API - ease of use
64+
config :ama, :seed64, (case System.get_env("SEED64") do nil -> nil; seed64 -> Base58.decode(seed64) end)
4865

49-
config :ama, :trainer_pk_b58, pk |> Base58.encode()
50-
config :ama, :trainer_pk, pk
51-
config :ama, :trainer_sk, System.get_env("SEED64") || sk
52-
config :ama, :trainer_pop, pop
5366

5467
config :ama, :archival_node, System.get_env("ARCHIVALNODE") in ["true", "y", "yes"]
5568
config :ama, :autoupdate, System.get_env("AUTOUPDATE") in ["true", "y", "yes"]
@@ -69,6 +82,10 @@ config :ama, :anr_next_refresh, 0
6982
config :ama, :anr_name, anr_name
7083
config :ama, :anr_desc, anr_desc
7184

85+
#TESTNET = true
86+
#TESTNET_TICK=true
87+
#write 10 validators to file
88+
7289
Path.join(work_folder, "ex/")
7390
|> Path.join("**/*.ex")
7491
|> Path.wildcard()

ex/lib/consensus/consensus.ex

Lines changed: 8 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -602,13 +602,13 @@ defmodule Consensus do
602602
#{m, m_rev, l, ConsensusKV.hash_mutations(l ++ m ++ m_rev)}
603603
mutations_hash = ConsensusKV.hash_mutations(l ++ m)
604604

605-
attestation = Attestation.sign(next_entry.hash, mutations_hash)
605+
sk = Application.fetch_env!(:ama, :trainer_sk)
606+
attestation = Attestation.sign(sk, next_entry.hash, mutations_hash)
606607
attestation_packed = Attestation.pack(attestation)
607608
RocksDB.put(next_entry.hash, attestation_packed, %{rtx: rtx, cf: cf.my_attestation_for_entry})
608609

609-
pk = Application.fetch_env!(:ama, :trainer_pk)
610610
trainers = trainers_for_height(Entry.height(next_entry), %{rtx: rtx, cf: cf})
611-
is_trainer = pk in trainers
611+
validator_seeds = Application.fetch_env!(:ama, :keys) |> Enum.filter(& &1.pk in trainers)
612612

613613
seen_time = :os.system_time(1000)
614614
RocksDB.put(next_entry.hash, seen_time, %{rtx: rtx, cf: cf.my_seen_time_for_entry, term: true})
@@ -642,29 +642,17 @@ defmodule Consensus do
642642

643643
:ok = RocksDB.transaction_commit(rtx)
644644

645-
ap = if is_trainer do
646-
#TODO: not ideal in super tight latency constrains but its 1 line and it works
647-
send(FabricCoordinatorGen, {:add_attestation, attestation})
648-
attestation_packed
649-
end
650-
651-
%{error: :ok, attestation_packed: ap, mutations_hash: mutations_hash, logs: l, muts: m}
645+
%{error: :ok, hash: next_entry.hash, validator_seeds: validator_seeds, mutations_hash: mutations_hash, logs: l, muts: m}
652646
end
653647

654-
def produce_entry(slot) do
655-
%{db: db, cf: cf} = :persistent_term.get({:rocksdb, Fabric})
656-
648+
def produce_entry(sk, slot) do
657649
cur_entry = chain_tip_entry()
658-
next_entry = Entry.build_next(cur_entry, slot)
650+
next_entry = Entry.build_next(sk, cur_entry, slot)
659651

660-
#TODO: todo add >1 tx
661-
#ts_m = :os.system_time(1000)
662-
#txs = TXPool.grab_next_valids(next_entry)
652+
#TODO: embed aggsig of previous vote
663653
txs = TXPool.grab_next_valid(100)
664-
#IO.inspect {:tx, :os.system_time(1000) - ts_m}
665-
666654
next_entry = Map.put(next_entry, :txs, txs)
667-
next_entry = Entry.sign(next_entry)
655+
next_entry = Entry.sign(sk, next_entry)
668656

669657
next_entry
670658
end

ex/lib/consensus/doms/attestation.ex

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,14 @@ defmodule Attestation do
66
signer: <>,
77
signature: <entry_hash,mutations_hash>,
88
}
9+
10+
ssz
11+
<<
12+
signature::96,
13+
signer::48,
14+
entry_hash::32,
15+
mutations_hash::32
16+
>>
917
"""
1018
def unpack(attestation_packed) when is_binary(attestation_packed) do
1119
a = :erlang.binary_to_term(attestation_packed, [:safe])
@@ -24,9 +32,8 @@ defmodule Attestation do
2432
|> :erlang.term_to_binary([:deterministic])
2533
end
2634

27-
def sign(entry_hash, mutations_hash) do
28-
pk = Application.fetch_env!(:ama, :trainer_pk)
29-
sk = Application.fetch_env!(:ama, :trainer_sk)
35+
def sign(sk, entry_hash, mutations_hash) do
36+
pk = BlsEx.get_public_key!(sk)
3037
signature = BlsEx.sign!(sk, <<entry_hash::binary, mutations_hash::binary>>, BLS12AggSig.dst_att())
3138
%{
3239
entry_hash: entry_hash,

ex/lib/consensus/doms/entry.ex

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,7 @@ defmodule Entry do
3636
|> :erlang.term_to_binary([:deterministic])
3737
end
3838

39-
def sign(entry_unpacked) do
40-
sk = Application.fetch_env!(:ama, :trainer_sk)
41-
39+
def sign(sk, entry_unpacked) do
4240
txs_hash = Blake3.hash(Enum.join(entry_unpacked.txs))
4341
entry_unpacked = put_in(entry_unpacked, [:header_unpacked, :txs_hash], txs_hash)
4442
h = :erlang.term_to_binary(entry_unpacked.header_unpacked, [:deterministic])
@@ -175,9 +173,8 @@ defmodule Entry do
175173
end
176174
end
177175

178-
def build_next(cur_entry, slot) do
179-
pk = Application.fetch_env!(:ama, :trainer_pk)
180-
sk = Application.fetch_env!(:ama, :trainer_sk)
176+
def build_next(sk, cur_entry, slot) do
177+
pk = BlsEx.get_public_key!(sk)
181178

182179
dr = Blake3.hash(cur_entry.header_unpacked.dr)
183180
vr = BlsEx.sign!(sk, cur_entry.header_unpacked.vr, BLS12AggSig.dst_vrf())

ex/lib/consensus/doms/entry_genesis.ex

Lines changed: 66 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,20 +122,84 @@ defmodule EntryGenesis do
122122
},
123123
txs: [],
124124
}
125-
entry_signed = Entry.sign(entry)
125+
entry_signed = Entry.sign(sk, entry)
126126

127127
%{db: db, cf: cf} = :persistent_term.get({:rocksdb, Fabric})
128128
rtx = RocksDB.transaction(db)
129129
Process.put({RocksDB, :ctx}, %{rtx: rtx, cf: cf})
130130
{mutations, _} = BIC.Base.call_exit(%{entry: entry})
131131

132132
mutations_hash = ConsensusKV.hash_mutations(mutations)
133-
attestation = Attestation.sign(entry_signed.hash, mutations_hash)
133+
attestation = Attestation.sign(sk, entry_signed.hash, mutations_hash)
134134

135135
pop = BlsEx.sign!(sk, pk, BLS12AggSig.dst_pop())
136136
entry_signed = Entry.pack(entry_signed) |> Entry.unpack()
137137

138138
IO.inspect {entry_signed, attestation, pop}, limit: :infinity
139139
:ok
140140
end
141+
142+
def generate_testnet() do
143+
%{db: db, cf: cf} = :persistent_term.get({:rocksdb, Fabric})
144+
if !RocksDB.get("temporal_height", %{db: db, cf: cf.sysconf}) do
145+
IO.puts "making testnet.."
146+
147+
pk = Application.fetch_env!(:ama, :trainer_pk)
148+
sk = Application.fetch_env!(:ama, :trainer_sk)
149+
150+
if length(Application.fetch_env!(:ama, :keys)) < 10 do
151+
new_keys = Enum.map(0..9, fn(_)-> :crypto.strong_rand_bytes(64) |> Base58.encode() end)
152+
|> Enum.join("\n")
153+
workdir = Application.fetch_env!(:ama, :work_folder)
154+
File.write!(Path.join([workdir, "seeds"]), new_keys)
155+
IO.puts "seeded testnet please restart node"
156+
:erlang.halt()
157+
end
158+
159+
entropy_seed = :crypto.strong_rand_bytes(512)
160+
dr = Blake3.hash(entropy_seed)
161+
vr = BlsEx.sign!(sk, dr<>dr<>dr, BLS12AggSig.dst_vrf())
162+
163+
entry = %{
164+
header_unpacked: %{
165+
slot: 0,
166+
height: 0,
167+
prev_slot: -1,
168+
prev_hash: <<>>,
169+
dr: dr,
170+
vr: vr,
171+
signer: pk,
172+
},
173+
txs: [],
174+
}
175+
entry_signed = Entry.sign(sk, entry)
176+
177+
178+
rtx = RocksDB.transaction(db)
179+
Process.put({RocksDB, :ctx}, %{rtx: rtx, cf: cf})
180+
181+
mutations_hash = ConsensusKV.hash_mutations([])
182+
attestation = Attestation.sign(sk, entry_signed.hash, mutations_hash)
183+
184+
pop = BlsEx.sign!(sk, pk, BLS12AggSig.dst_pop())
185+
entry_signed = Entry.pack(entry_signed) |> Entry.unpack()
186+
187+
RocksDB.put(entry_signed.hash, Entry.pack(entry_signed), %{rtx: rtx, cf: cf.entry})
188+
RocksDB.put(entry_signed.hash, :os.system_time(1000), %{rtx: rtx, cf: cf.my_seen_time_for_entry, term: true})
189+
RocksDB.put("temporal_tip", entry_signed.hash, %{rtx: rtx, cf: cf.sysconf})
190+
RocksDB.put("temporal_height", 0, %{rtx: rtx, cf: cf.sysconf, term: true})
191+
RocksDB.put("rooted_tip", entry_signed.hash, %{rtx: rtx, cf: cf.sysconf})
192+
193+
validator_pks = Application.fetch_env!(:ama, :keys) |> Enum.map(& &1.pk)
194+
RocksDB.put("bic:epoch:trainers:height:#{String.pad_leading("0", 12, "0")}",
195+
:erlang.term_to_binary(validator_pks), %{rtx: rtx, cf: cf.contractstate})
196+
Enum.each(Application.fetch_env!(:ama, :keys), fn(key)->
197+
RocksDB.put("bic:coin:balance:#{key.pk}:AMA", "1001000000000", %{rtx: rtx, cf: cf.contractstate})
198+
RocksDB.put("bic:epoch:pop:#{key.pk}", key.pop, %{rtx: rtx, cf: cf.contractstate})
199+
end)
200+
rtx = RocksDB.transaction_commit(rtx)
201+
202+
#Fabric.aggregate_attestation(attestation |> Attestation.pack())
203+
end
204+
end
141205
end

ex/lib/consensus/fabric_gen.ex

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ defmodule FabricGen do
5050

5151
def tick_slot(state) do
5252
#IO.inspect "tick_slot"
53+
Application.fetch_env!(:ama, :testnet) && Process.sleep(500)
54+
5355
if proc_if_my_slot() do
5456
proc_entries()
5557
#proc_compact()
@@ -200,23 +202,27 @@ defmodule FabricGen do
200202
#IO.inspect {:took, entry.header_unpacked.height, :os.system_time(1000) - ts_s}
201203

202204
task = Task.async(fn -> Consensus.apply_entry(entry) end)
203-
%{error: :ok, attestation_packed: attestation_packed,
205+
%{error: :ok, hash: hash, validator_seeds: vseeds,
204206
mutations_hash: m_hash, logs: l, muts: m
205207
} = case Task.await(task, :infinity) do
206208
result = %{error: :ok} -> result
207209
end
208210

209211
FabricEventGen.event_applied(entry, m_hash, m, l)
210212

211-
if !!attestation_packed and FabricSyncAttestGen.isQuorumSyncedOffByX(6) do
212-
msg = NodeProto.event_attestation(attestation_packed)
213-
NodeGen.broadcast(msg)
213+
Enum.each(vseeds, fn(seed)->
214+
attestation = Attestation.sign(seed.seed, hash, m_hash)
215+
send(FabricCoordinatorGen, {:add_attestation, attestation})
216+
if FabricSyncAttestGen.isQuorumSyncedOffByX(6) do
217+
msg = NodeProto.event_attestation(Attestation.pack(attestation))
218+
NodeGen.broadcast(msg)
214219

215-
#Ensure RPC nodes are as up-to-date as possible
216-
#TODO: fix this in a better way later
217-
peers = Application.fetch_env!(:ama, :seedanrs_as_peers)
218-
send(NodeGen.get_socket_gen(), {:send_to, peers, msg})
219-
end
220+
#Ensure RPC nodes are as up-to-date as possible
221+
#TODO: fix this in a better way later
222+
peers = Application.fetch_env!(:ama, :seedanrs_as_peers)
223+
send(NodeGen.get_socket_gen(), {:send_to, peers, msg})
224+
end
225+
end)
220226

221227
TXPool.delete_packed(entry.txs)
222228

@@ -225,7 +231,6 @@ defmodule FabricGen do
225231
end
226232

227233
def proc_if_my_slot() do
228-
pk = Application.fetch_env!(:ama, :trainer_pk)
229234
entry = Consensus.chain_tip_entry()
230235
next_slot = entry.header_unpacked.slot + 1
231236
next_height = entry.header_unpacked.height + 1
@@ -239,13 +244,15 @@ defmodule FabricGen do
239244
|> Enum.filter(& &1.header_unpacked.prev_hash == rooted_tip)
240245
emptyHeight = emptyHeight == []
241246

247+
am_i_next = Enum.find(Application.fetch_env!(:ama, :keys), & &1.pk == slot_trainer)
248+
242249
cond do
243250
!FabricSyncAttestGen.isQuorumSynced() -> nil
244251

245252
lastSlot == next_slot -> nil
246253
!emptyHeight -> nil
247254

248-
pk == slot_trainer ->
255+
am_i_next ->
249256
:persistent_term.put(:last_made_entry_slot, next_slot)
250257

251258
if :persistent_term.get(:snapshot_before_my_slot, nil) do
@@ -254,17 +261,17 @@ defmodule FabricGen do
254261
FabricSnapshot.snapshot_tmp()
255262
end
256263

257-
IO.puts "🔧 im in slot #{next_slot}, working.. *Click Clak*"
264+
!Application.fetch_env!(:ama, :testnet) && IO.puts("🔧 im in slot #{next_slot}, working.. *Click Clak*")
258265

259-
proc_if_my_slot_1(next_slot)
266+
proc_if_my_slot_1(am_i_next.seed, next_slot)
260267

261268
true ->
262269
nil
263270
end
264271
end
265272

266-
def proc_if_my_slot_1(next_slot) do
267-
next_entry = Consensus.produce_entry(next_slot)
273+
def proc_if_my_slot_1(seed, next_slot) do
274+
next_entry = Consensus.produce_entry(seed, next_slot)
268275
Fabric.insert_entry(next_entry, :os.system_time(1000))
269276

270277
msg = NodeProto.event_entry(Entry.pack(next_entry))

ex/lib/consensus/fabric_sync_attest_gen.ex

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ defmodule FabricSyncAttestGen do
5454

5555
def isQuorumSynced() do
5656
cond do
57+
Application.fetch_env!(:ama, :testnet) -> true
5758
!hasQuorum() -> false
5859
isSynced() != :full -> false
5960
Fabric.rooted_tip_height() < Consensus.chain_height() -> false

ex/lib/consensus/special_meeting/special_meeting_gen.ex

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -160,17 +160,18 @@ defmodule SpecialMeetingGen do
160160

161161
def build_slash_entry(st) do
162162
my_pk = Application.fetch_env!(:ama, :trainer_pk)
163+
sk = Application.fetch_env!(:ama, :trainer_sk)
163164
packed_tx = build_slash_tx(st)
164165

165166
true = FabricSyncAttestGen.isQuorumSynced()
166167
cur_entry = Fabric.rooted_tip_entry()
167168
cur_height = cur_entry.header_unpacked.height
168169
cur_slot = cur_entry.header_unpacked.slot
169170

170-
next_entry = Entry.build_next(cur_entry, cur_slot + 1)
171+
next_entry = Entry.build_next(sk, cur_entry, cur_slot + 1)
171172
txs = [packed_tx]
172173
next_entry = Map.put(next_entry, :txs, txs)
173-
next_entry = Entry.sign(next_entry)
174+
next_entry = Entry.sign(sk, next_entry)
174175

175176
trainers = Consensus.trainers_for_height(next_entry.header_unpacked.height + 1)
176177
mask = <<0::size(length(trainers))>>

0 commit comments

Comments
 (0)