diff --git a/apps/tpic2/src/tpic2_tls.erl b/apps/tpic2/src/tpic2_tls.erl index b4979549..61468b65 100644 --- a/apps/tpic2/src/tpic2_tls.erl +++ b/apps/tpic2/src/tpic2_tls.erl @@ -55,22 +55,39 @@ loop1(State=#{socket:=Socket,role:=Role,opts:=Opts,transport:=Transport}) -> undefined end, IsItMe=tpecdsa:cmp_pubkey(Pubkey)==tpecdsa:cmp_pubkey(nodekey:get_pub()), + IsOurNode=chainsettings:is_our_node(Pubkey), ?LOG_INFO("Peer PubKey ~s ~p",[hex:encode(Pubkey), - try - chainsettings:is_our_node(Pubkey) - catch _:_ -> unkn0wn - end]), - case {IsItMe,Role} of - {true, server} -> - ?LOG_NOTICE("Looks like I received connection from myself, dropping session"), + try IsOurNode catch _:_ -> unkn0wn end]), + if IsItMe andalso Role==server -> + ?LOG_NOTICE("I received connection from myself, dropping session"), + timer:sleep(1000), + Transport:close(Socket), done; - {true, _} -> - ?LOG_NOTICE("Looks like I received connected to myself, dropping session"), + + IsItMe -> + ?LOG_NOTICE("I connected to myself, dropping session"), + timer:sleep(1000), + Transport:close(Socket), + done; + + Role == server andalso IsOurNode == false -> %server, unknonwn peer + tpic2_tls:send_msg(unknown_node, State), + timer:sleep(1000), + Transport:close(Socket), done; - {false, server} -> + + Role == server -> %server, known peer {ok,PPID}=gen_server:call(tpic2_cmgr, {peer,Pubkey, {register, undefined, in, self()}}), ?MODULE:loop(State#{pubkey=>Pubkey,peerpid=>PPID}); - {false, _} -> + + IsOurNode == false -> %client unknown node + {IP, Port} = maps:get(address, State), + gen_server:call(tpic2_cmgr,{peer, Pubkey, {del, IP, Port}, unknown_node}), + timer:sleep(5000), + Transport:close(Socket), + done; + + true -> %client, known node Stream=maps:get(stream, Opts, 0), {IP, Port} = maps:get(address, State), gen_server:call(tpic2_cmgr,{peer, Pubkey, {add, IP, Port}}), @@ -208,6 +225,11 @@ send_msg(hello, #{socket:=Socket, opts:=Opts}) -> ?LOG_DEBUG("Hello ~p",[Hello]), ssl:send(Socket,msgpack:pack(Hello)); +send_msg(unknown_node, #{socket:=Socket, opts:=Opts}) -> + ?LOG_DEBUG("send unknown_node and close conn to ~p",[Opts]), + Hello=#{null=><<"unknown_node">>}, + ssl:send(Socket,msgpack:pack(Hello)); + send_msg(Msg, #{socket:=Socket}) when is_map(Msg) -> ssl:send(Socket,msgpack:pack(Msg)). diff --git a/apps/tpnode/src/block.erl b/apps/tpnode/src/block.erl index 450952fa..6fdaaf99 100644 --- a/apps/tpnode/src/block.erl +++ b/apps/tpnode/src/block.erl @@ -68,7 +68,7 @@ prepack(Block) -> maps:from_list( lists:map( fun({TxID, T}) -> - {TxID, tx:pack(T)} + {TxID, pack_patch(T)} end, Txs) ); (inbound_blocks, Blocks) -> @@ -372,6 +372,8 @@ verify(#{ header:=#{parent:=Parent, %blkv2 {settings_hash, SH}; ({<<"settings_hash">>, SH}) -> {settings_hash, SH}; + ({<<"log_hash">>, SH}) -> + {log_hash, SH}; ({Key, Value}) -> ?LOG_INFO("Unknown root ~p",[Key]), {Key, Value} @@ -507,11 +509,15 @@ verify(#{ header:=#{parent:=_, binarize_settings([]) -> []; -binarize_settings([{TxID, #{ kind:=patch, ver:=2, patches:=_ }=Patch}|Rest]) -> - [{TxID, tx:pack(Patch)}|binarize_settings(Rest)]; -binarize_settings([{TxID, #{ patch:=_LPatch }=Patch}|Rest]) -> - [{TxID, tx:pack(Patch)}|binarize_settings(Rest)]. - +binarize_settings([{TxID, Patch}|Rest]) -> + [{TxID, pack_patch(Patch)}|binarize_settings(Rest)]. + +%pack_patch(#{ patch:=P }) -> +% tx:pack(tx:construct_tx(#{patches=>P, kind=>patch, ver=>2})); +pack_patch(#{ kind:=patch, ver:=2, patches:=_, body:=_ }=Patch) -> + tx:pack(Patch); +pack_patch(#{ kind:=patch, ver:=2, patches:=_ }=Patch) -> + tx:pack(tx:construct_tx(Patch)). mkblock2(#{ txs:=Txs, parent:=Parent, height:=H, bals:=Bals0, diff --git a/apps/tpnode/src/blockchain_sync.erl b/apps/tpnode/src/blockchain_sync.erl index bb68f11a..28db59f1 100644 --- a/apps/tpnode/src/blockchain_sync.erl +++ b/apps/tpnode/src/blockchain_sync.erl @@ -7,7 +7,7 @@ %% API Function Exports %% ------------------------------------------------------------------ --export([start_link/0,chainstate/0,bbyb_sync/3,receive_block/2,tpiccall/3]). +-export([start_link/0,chainstate/0,bbyb_sync/3,receive_block/2,tpiccall/3,sort_rnd/1]). %% ------------------------------------------------------------------ %% gen_server Function Exports @@ -31,7 +31,7 @@ chainstate() -> ))++[{self,gen_server:call(blockchain_reader,sync_req)}], % io:format("Cand ~p~n",[Candidates]), ChainState=lists:foldl( %first suitable will be the quickest - fun({_, #{chain:=_HisChain, + fun({PK0, #{chain:=_HisChain, %null:=<<"sync_available">>, last_hash:=Hash, last_temp:=Tmp, @@ -39,9 +39,19 @@ chainstate() -> last_height:=Heig }=A }, Acc) -> + PK=case PK0 of + self -> nodekey:node_name(); + {HisKey,_,_} -> + case chainsettings:is_our_node(HisKey) of + false -> + hex:encode(HisKey); + OurName -> + OurName + end + end, PHash=maps:get(prev_hash,A,<<0,0,0,0,0,0,0,0>>), maps:put({Heig, Hash, PHash, Tmp}, - maps:get({Heig, Hash, PHash, Tmp}, Acc, 0)+1, Acc); + [PK|maps:get({Heig, Hash, PHash, Tmp}, Acc, [])], Acc); ({_, _}, Acc) -> Acc end, #{}, Candidates), @@ -54,7 +64,7 @@ chainstate() -> ":",blkid(Has), "/",blkid(PHas),":", integer_to_list(if Tmp==false -> 0; true -> Tmp end) - ]),V,Acc) + ]),length(V),Acc) end, #{}, ChainState)), ChainState. @@ -243,11 +253,10 @@ handle_info(runsync, State) -> Candidates = case maps:get(sync_candidates, State, []) of [] -> ?LOG_DEBUG("use default list of candidates"), - lists:reverse( - tpiccall(<<"blockchain">>, - #{null=><<"sync_request">>}, - [last_hash, last_height, chain, last_temp] - )); + sort_rnd(tpiccall(<<"blockchain">>, + #{null=><<"sync_request">>}, + [last_hash, last_height, chain, last_temp] + )); SavedCandidates -> ?LOG_DEBUG("use saved list of candidates"), SavedCandidates @@ -262,15 +271,15 @@ handle_info({runsync, Candidates}, State) -> }, hash:=MyLastHash}=MyLast=blockchain:last_meta(), B=tpiccall(<<"blockchain">>, - #{null=><<"sync_request">>}, - [last_hash, last_height, chain, last_temp] - ), + #{null=><<"sync_request">>}, + [last_hash, last_height, chain, last_temp] + ), Hack_Candidates=lists:foldl( fun({{A1,B1,_},_}=Elem, Acc) -> maps:put({A1,B1},Elem,Acc) end, #{}, B), - Candidate=lists:foldl( %first suitable will be the quickest + Candidate=lists:foldl( fun ({{A2,B2,_}, undefined}, undefined) -> case maps:find({A2,B2},Hack_Candidates) of @@ -589,4 +598,10 @@ skip_candidate(default)-> skip_candidate(Candidates) when is_list(Candidates) -> tl(Candidates). +sort_rnd(List) -> + List0=[ {rand:uniform(), I} || I <- List ], + List1=lists:keysort(1, List0), + [ E || {_,E} <- List1 ]. + + %% ------------------------------------------------------------------ diff --git a/apps/tpnode/src/bsig.erl b/apps/tpnode/src/bsig.erl index 8c97b667..088a68b3 100644 --- a/apps/tpnode/src/bsig.erl +++ b/apps/tpnode/src/bsig.erl @@ -105,9 +105,8 @@ encode_edval(N, PK) when is_binary(N) andalso is_binary(PK) -> end; encode_edval(_, _) -> <<>>. -splitsig(<<255, SLen:8/integer, Rest/binary>>) -> - <>=Rest, - {Signature, Extradata}. +splitsig(<<255, SLen:8/integer, Signature:SLen/binary, Rest/binary>>) -> + {Signature, Rest}. unpacksig(HSig) when is_map(HSig) -> HSig; diff --git a/apps/tpnode/src/chainsettings.erl b/apps/tpnode/src/chainsettings.erl index 39320e87..01efd405 100644 --- a/apps/tpnode/src/chainsettings.erl +++ b/apps/tpnode/src/chainsettings.erl @@ -8,6 +8,7 @@ is_our_node/2, settings_to_ets/1, all/0, by_path/1]). +-export([contacts/1,contacts/2]). -export([checksum/0]). is_our_node(PubKey, Settings) -> @@ -93,6 +94,42 @@ settings_to_ets(NewSettings) -> blockchain_updater:store_mychain(MyName, ChainNodes, MyChain), NewSettings. +contacts(Name, Protocol) when is_binary(Protocol) -> + contacts(Name, [Protocol]); + +contacts(Name, Protocols) when is_list(Protocols) -> + C=contacts(Name), + lists:foldl( + fun(URL,A) -> + try + #{scheme:=P}=uri_string:parse(URL), + case lists:member(P,Protocols) of + true -> + [URL|A]; + false -> + A + end + catch _:_ -> + A + end + end, [], C). + +contacts(Name) -> + Config = application:get_env(tpnode, contacts, #{}), + R=case maps:get(Name, Config, undefined) of + Value when is_list(Value) -> + Value; + undefined -> + chainsettings:by_path([<<"contacts">>,<<"default">>,Name]); + Any -> + logger:notice("Error value for contact ~p in config: ~p",[Name,Any]), + chainsettings:by_path([<<"contacts">>,<<"default">>,Name]) + end, + if R==#{} -> + []; + true -> + R + end. get_val(Name) -> get_val(Name, undefined). diff --git a/apps/tpnode/src/generate_block.erl b/apps/tpnode/src/generate_block.erl index db370c3e..799056a9 100644 --- a/apps/tpnode/src/generate_block.erl +++ b/apps/tpnode/src/generate_block.erl @@ -13,8 +13,19 @@ generate_block(PreTXL, {Parent_Height, Parent_Hash}, GetSettings, GetAddr, Extra %file:write_file("tmp/tx.txt", io_lib:format("~p.~n", [PreTXL])), _T1=erlang:system_time(), _T2=erlang:system_time(), - TXL=sort_txs(PreTXL), XSettings=GetSettings(settings), + PreTXL1=lists:filter( + fun({TxID,#{not_before:=DT}}) -> + L=settings:get([<<"current">>,<<"delaytx">>,DT], XSettings), + if is_list(L) -> + lists:member(TxID,L); + true -> + false + end; + (_) -> true + end, PreTXL), + + TXL=sort_txs(PreTXL1), Addrs0=lists:foldl( fun(default, Acc) -> BinAddr=naddress:construct_private(0, 0), @@ -441,7 +452,7 @@ update_aalloc(#{ IncAddr=#{<<"t">> => <<"set">>, <<"p">> => [<<"current">>, <<"allocblock">>, <<"last">>], <<"v">> => CA}, - AAlloc={<<"aalloc">>, #{sig=>[], patch=>[IncAddr]}}, + AAlloc={<<"aalloc">>, #{sig=>[], ver=>2, kind=>patch, patches=>[IncAddr]}}, SS1=settings:patch(AAlloc, SetState), Acc#{new_settings=>SS1, @@ -497,7 +508,7 @@ cleanup_delayed(#{delayed:=DTX, new_settings:=NS, settings:=Sets} = Acc) -> Cleanup=[#{<<"p">>=>[<<"current">>,<<"delaytx">>], <<"t">>=><<"lists_cleanup">>, <<"v">>=><<"empty_list">>}], - DelPatch={<<"cleanjob">>, #{sig=>[], patch=>ToDel++Cleanup}}, + DelPatch={<<"cleanjob">>, #{sig=>[], ver=>2, kind=>patch, patches=>ToDel++Cleanup}}, ?LOG_INFO("Patches ~p~n",[ToDel]), Acc#{ settings=>[DelPatch|Sets] @@ -536,7 +547,7 @@ process_delayed_txs(#{emit:=Emit, settings:=Settings, parent:=P, _ -> Patches=[#{<<"p">> => [<<"current">>,<<"delaytx">>,Timestamp], <<"t">> => <<"list_add">>,<<"v">> => [H,P,TxID]} || {TxID, Timestamp} <- ToSet ], - SyncPatch={<<"delayjob">>, #{sig=>[], patch=>Patches}}, + SyncPatch={<<"delayjob">>, #{sig=>[], ver=>2, kind=>patch, patches=>Patches}}, ?LOG_INFO("Emit ~p~n",[NewEmit]), ?LOG_INFO("Patches ~p~n",[Patches]), diff --git a/apps/tpnode/src/generate_block_process.erl b/apps/tpnode/src/generate_block_process.erl index de7fc542..bd6ac22d 100644 --- a/apps/tpnode/src/generate_block_process.erl +++ b/apps/tpnode/src/generate_block_process.erl @@ -20,9 +20,79 @@ }. -spec try_process([{_,_}], mkblock_acc()) -> mkblock_acc(). -try_process([], Acc) -> +try_process([], #{ + settings:=Settings, + parent:=ParentHash, + height:=MyHeight, + new_settings:=SetState, + outbound:=Outbound + }=Acc) -> + OutChains = lists:usort([Chain || {_, Chain} <- Outbound]), + {SS2, Set2}=lists:foldl( + fun(OutTo, {SS, Set}) -> + PatchTxID= <<"out", (xchain:pack_chid(OutTo))/binary>>, + ChainPath=[<<"current">>, <<"outward">>, + xchain:pack_chid(OutTo)], + SyncSet=settings:get(ChainPath, SS), + PC1=case SyncSet of + #{<<".">>:=#{<<"height">>:=#{<<"ublk">>:=UBLK}}} -> + [ + #{<<"t">> =><<"set">>, + <<"p">> => ChainPath ++ [<<"pre_hash">>], + <<"v">> => UBLK + } + ]; + _ -> [] + end, + PC2=case SyncSet of + #{<<"parent">>:=PP} -> + [ + #{<<"t">> =><<"set">>, + <<"p">> => ChainPath ++ [<<"pre_parent">>], + <<"v">> => PP + } + ]; + _ -> + [] + end, + PC3=case SyncSet of + #{<<"height">>:=HH} -> + [ + #{<<"t">> =><<"set">>, + <<"p">> => ChainPath ++ [<<"pre_height">>], + <<"v">> => HH + } + ]; + _ -> + [] + end, + PCP=if PC1==[] andalso PC2==[] andalso PC3==[] -> + [ + #{<<"t">> =><<"set">>, + <<"p">> => ChainPath ++ [<<"pre_hash">>], + <<"v">> => <<0,0,0,0,0,0,0,0>> + }, + #{<<"t">> =><<"set">>, + <<"p">> => ChainPath ++ [<<"pre_height">>], + <<"v">> => 0 + } + ]; + true -> + PC1++PC2++PC3 + end, + IncPtr=[ + #{<<"t">> => <<"set">>, <<"p">> => ChainPath ++ [<<"parent">>], <<"v">> => ParentHash }, + #{<<"t">> => <<"set">>, <<"p">> => ChainPath ++ [<<"height">>], <<"v">> => MyHeight } + |PCP ], + SyncPatch={PatchTxID, #{sig=>[], ver=>2, kind=>patch, patches=>IncPtr}}, + { + settings:patch(SyncPatch, SS), + [SyncPatch|Set] + } + end, {SetState, Settings}, OutChains), + ?LOG_INFO("try_process finish"), - Acc; + Acc#{settings=>Set2, set_state=>SS2}; %process inbound block try_process([{BlID, #{ hash:=BHash, @@ -61,7 +131,7 @@ try_process([{BlID, #{ hash:=BHash, } ], PatchTxID= <<"sync", (xchain:pack_chid(ChID))/binary>>, - SyncPatch={PatchTxID, #{sig=>[], patch=>IncPtr}}, + SyncPatch={PatchTxID, #{sig=>[], ver=>2, kind=>patch, patches=>IncPtr}}, if P==undefined -> ?LOG_NOTICE("Old block without settings"), try_process([ {TxID, @@ -583,10 +653,8 @@ try_process([{TxID, #{ NewF1=maps:remove(keep, mbal:put(view, NewView, NewF) ), - ?LOG_INFO("F1 ~p",[maps:without([code,state],NewF1)]), NewF2=return_gas(Gas, SetState, NewF1), - ?LOG_INFO("F2 ~p",[maps:without([code,state],NewF2)]), NewAddresses=maps:put(Owner, NewF2, Addresses), try_process(Rest, @@ -695,12 +763,12 @@ try_process([{TxID, #{from:=From, to:=To}=Tx} |Rest], % SetState, Addresses, GetFun, #{failed:=Failed, %table:=Addresses, - %new_settings:=SetState, + new_settings:=SetState, get_settings:=GetFun }=Acc) -> MyChain=GetFun(mychain), - FAddr=addrcheck(From), - TAddr=addrcheck(To), + FAddr=addrcheck(From, SetState, MyChain), + TAddr=addrcheck(To, SetState, MyChain), case {FAddr, TAddr} of {{true, {chain, MyChain}}, {true, {chain, MyChain}}} -> try_process_local([{TxID, Tx}|Rest], Acc); @@ -709,18 +777,21 @@ try_process([{TxID, #{from:=From, to:=To}=Tx} |Rest], outbound=>OtherChain }}|Rest], Acc); - {{true, {chain, _OtherChain}}, {true, {chain, MyChain}}} -> + {{true, {chain, _FromChain}}, {true, {chain, MyChain}}} -> try_process_inbound([{TxID, - maps:remove(outbound, - Tx - )}|Rest], + maps:remove(outbound, Tx)}|Rest], Acc); + {{true, private}, {true, private}} -> %pvt + try_process_local([{TxID, Tx}|Rest], Acc); {{true, private}, {true, {chain, MyChain}}} -> %local from pvt - try_process_local([{TxID, Tx}|Rest], - Acc); + try_process_local([{TxID, Tx}|Rest], Acc); {{true, {chain, MyChain}}, {true, private}} -> %local to pvt - try_process_local([{TxID, Tx}|Rest], - Acc); + try_process_local([{TxID, Tx}|Rest], Acc); + {{true, {chain, _}}, false} -> + ?LOG_INFO("TX ~s dst addr error ~p", [TxID, TAddr]), + try_process(Rest, + Acc#{failed=>[{TxID, 'bad_dst_addr'}|Failed], + last => failed}); _ -> ?LOG_INFO("TX ~s addr error ~p -> ~p", [TxID, FAddr, TAddr]), try_process(Rest, @@ -739,6 +810,7 @@ try_process_inbound([{TxID, kind:=generic, from:=From, to:=To, + t:=T, origin_block:=OriginBlock, origin_block_height:=OriginHeight, origin_block_hash:=OriginHash, @@ -750,8 +822,9 @@ try_process_inbound([{TxID, table:=Addresses, new_settings:=SetState, emit:=Emit, + outbound:=Outbound, pick_block:=PickBlock}=Acc) -> - ?LOG_ERROR("Check signature once again"), + ?LOG_INFO("Check signature once again"), try Gas=case tx:get_ext(<<"xc_gas">>, Tx) of undefined -> {<<"NONE">>,0,{1,1}}; @@ -764,106 +837,156 @@ try_process_inbound([{TxID, end end, - ?LOG_INFO("Orig Block ~p", [OriginBlock]), - {Addresses2, NewEmit, GasLeft, Acc1, AddEd}=deposit(TxID, To, Addresses, Tx, Gas, Acc), - %Addresses2=maps:put(To, NewT, Addresses), - - NewAddresses=case GasLeft of - {_, 0, _} -> - Addresses2; - {_, IGL, _} when IGL < 0 -> - throw('insufficient_gas'); - {_, IGL, _} when IGL > 0 -> - ?LOG_NOTICE("Return gas ~p to sender",[From]), - Addresses2 - end, - - TxExt=maps:get(extdata,Tx,#{}), - NewExt=maps:merge( - TxExt#{ - <<"orig_bhei">>=>OriginHeight, - <<"orig_bhash">>=>OriginHash, - <<"orig_chain">>=>ChID - }, maps:from_list(AddEd) - ), - FixTX=maps:without( - [origin_block,origin_block_height, origin_block_hash, origin_chain], - Tx#{extdata=>NewExt} - ), - try_process(Rest, - Acc1#{success=>[{TxID, FixTX}|Success], - emit => Emit ++ NewEmit, - table => NewAddresses, - pick_block=>maps:put(OriginBlock, 1, PickBlock), - last => ok - }) - catch throw:X -> - try_process(Rest, - Acc#{failed=>[{TxID, X}|Failed], - last => failed}) - end; + try + ?LOG_INFO("Orig Block ~p", [OriginBlock]), + {NewAddresses, NewEmit, GasLeft, Acc1, AddEd}=deposit(TxID, To, Addresses, Tx, Gas, Acc), + %Addresses2=maps:put(To, NewT, Addresses), + + RetGas=case GasLeft of + {_, 0, _} -> + false; + {_, IGL, _} when IGL < 0 -> + throw('insufficient_gas'); + {Token, IGL, _} when IGL > 50 -> + %TODO: take this minimal return limit from somewhere + ?LOG_INFO("Return gas ~p to sender ~p",[{Token,IGL},From]), + {Token, IGL}; + _ -> + false + end, + io:format("RetGas ~p to address ~p chain ~p~n",[RetGas, From, ChID]), + + TxExt=maps:get(extdata,Tx,#{}), + NewExt=maps:merge( + TxExt#{ + <<"orig_bhei">>=>OriginHeight, + <<"orig_bhash">>=>OriginHash, + <<"orig_chain">>=>ChID + }, maps:from_list(AddEd) + ), + FixTX=maps:without( + [origin_block,origin_block_height, origin_block_hash, origin_chain], + Tx#{extdata=>NewExt} + ), + + + case RetGas of + false -> + try_process(Rest, + savegas(Gas, all, + Acc1#{success=>[{TxID, FixTX}|Success], + emit => Emit ++ NewEmit, + table => NewAddresses, + pick_block=>maps:put(OriginBlock, 1, PickBlock), + last => ok + }) + ); + {Tkn, Amount} -> + TxID2= <>, + Tx2=tx:construct_tx( + #{kind=>generic, + ver=>2, + from=>To, + to=>From, + payload=>[ + #{purpose=>transfer, cur=>Tkn, amount=>Amount } + ], + txext=>#{<<"xc_retgas">> => true}, + seq=>0, + t=>T + }), + + try_process(Rest, + savegas(Gas, GasLeft, + Acc1#{success=>[{TxID, FixTX},{TxID2, Tx2}|Success], + emit => Emit ++ NewEmit, + table => NewAddresses, + outbound=>[{TxID2, ChID}|Outbound], + pick_block=>maps:put(OriginBlock, 1, PickBlock), + last => ok + }) + ) + end -try_process_inbound([{TxID, - #{cur:=Cur, amount:=Amount, to:=To, - origin_block:=OriginBlock, - origin_block_height:=OriginHeight, - origin_block_hash:=OriginHash, - origin_chain:=ChID - }=Tx} - |Rest], - #{success:=Success, - table:=Addresses, - failed:=Failed, - pick_block:=PickBlock}=Acc) -> - ?LOG_NOTICE("Check signature once again"), - TBal=maps:get(To, Addresses), - try - ?LOG_DEBUG("Orig Block ~p", [OriginBlock]), - if Amount >= 0 -> ok; - true -> throw ('bad_amount') - end, - NewTAmount=mbal:get_cur(Cur, TBal) + Amount, - NewT=maps:remove(keep, - mbal:put_cur( - Cur, - NewTAmount, - TBal) - ), - NewAddresses=maps:put(To, NewT, Addresses), - TxExt=maps:get(extdata,Tx,#{}), - NewExt=TxExt#{ - <<"orig_bhei">>=>OriginHeight, - <<"orig_bhash">>=>OriginHash, - <<"orig_chain">>=>ChID - }, - FixTX=maps:without( - [origin_block,origin_block_height, origin_block_hash, origin_chain], - Tx#{extdata=>NewExt} - ), - try_process(Rest, - Acc#{success=>[{TxID, FixTX}|Success], - table => NewAddresses, - pick_block=>maps:put(OriginBlock, 1, PickBlock), - last => ok - }) - catch throw:X -> + catch + throw:insufficient_gas -> + try_process(Rest, + savegas(Gas, all, + Acc#{failed=>[{TxID, insufficient_gas}|Failed], + last => failed + } + ) + ) + end + catch + throw:X -> try_process(Rest, Acc#{failed=>[{TxID, X}|Failed], last => failed}) end. +%try_process_inbound([{TxID, +% #{cur:=Cur, amount:=Amount, to:=To, +% origin_block:=OriginBlock, +% origin_block_height:=OriginHeight, +% origin_block_hash:=OriginHash, +% origin_chain:=ChID +% }=Tx} +% |Rest], +% #{success:=Success, +% table:=Addresses, +% failed:=Failed, +% pick_block:=PickBlock}=Acc) -> +% TBal=maps:get(To, Addresses), +% try +% ?LOG_DEBUG("Orig Block ~p", [OriginBlock]), +% if Amount >= 0 -> ok; +% true -> throw ('bad_amount') +% end, +% NewTAmount=mbal:get_cur(Cur, TBal) + Amount, +% NewT=maps:remove(keep, +% mbal:put_cur( +% Cur, +% NewTAmount, +% TBal) +% ), +% NewAddresses=maps:put(To, NewT, Addresses), +% TxExt=maps:get(extdata,Tx,#{}), +% NewExt=TxExt#{ +% <<"orig_bhei">>=>OriginHeight, +% <<"orig_bhash">>=>OriginHash, +% <<"orig_chain">>=>ChID +% }, +% FixTX=maps:without( +% [origin_block,origin_block_height, origin_block_hash, origin_chain], +% Tx#{extdata=>NewExt} +% ), +% try_process(Rest, +% Acc#{success=>[{TxID, FixTX}|Success], +% table => NewAddresses, +% pick_block=>maps:put(OriginBlock, 1, PickBlock), +% last => ok +% }) +% catch throw:X -> +% try_process(Rest, +% Acc#{failed=>[{TxID, X}|Failed], +% last => failed}) +% end. + try_process_outbound([{TxID, - #{outbound:=OutTo, to:=To, from:=From}=Tx} + #{ + ver:=2, + outbound:=OutTo, + to:=To, + from:=From + }=Tx} |Rest], #{failed:=Failed, success:=Success, - settings:=Settings, outbound:=Outbound, table:=Addresses, get_settings:=GetFun, - new_settings:=SetState, - parent:=ParentHash, - height:=MyHeight + new_settings:=SetState }=Acc) -> ?LOG_INFO("Processing outbound ==[ ~s ]=======",[TxID]), ?LOG_NOTICE("TODO:Check signature once again"), @@ -874,76 +997,6 @@ try_process_outbound([{TxID, {NewF, _GasF, GotFee, GotGas}=withdraw(FBal, Tx, GetFun, SetState, []), ?LOG_INFO("Got gas ~p",[GotGas]), - PatchTxID= <<"out", (xchain:pack_chid(OutTo))/binary>>, - {SS2, Set2}=case lists:keymember(PatchTxID, 1, Settings) of - true -> - {SetState, Settings}; - false -> - ChainPath=[<<"current">>, <<"outward">>, - xchain:pack_chid(OutTo)], - SyncSet=settings:get(ChainPath, SetState), - PC1=case SyncSet of - #{<<".">>:=#{<<"height">>:=#{<<"ublk">>:=UBLK}}} -> - [ - #{<<"t">> =><<"set">>, - <<"p">> => ChainPath ++ [<<"pre_hash">>], - <<"v">> => UBLK - } - ]; - _ -> [] - end, - PC2=case SyncSet of - #{<<"parent">>:=PP} -> - [ - #{<<"t">> =><<"set">>, - <<"p">> => ChainPath ++ [<<"pre_parent">>], - <<"v">> => PP - } - ]; - _ -> - [] - end, - PC3=case SyncSet of - #{<<"height">>:=HH} -> - [ - #{<<"t">> =><<"set">>, - <<"p">> => ChainPath ++ [<<"pre_height">>], - <<"v">> => HH - } - ]; - _ -> - [] - end, - PCP=if PC1==[] andalso PC2==[] andalso PC3==[] -> - [ - #{<<"t">> =><<"set">>, - <<"p">> => ChainPath ++ [<<"pre_hash">>], - <<"v">> => <<0,0,0,0,0,0,0,0>> - }, - #{<<"t">> =><<"set">>, - <<"p">> => ChainPath ++ [<<"pre_height">>], - <<"v">> => 0 - } - ]; - true -> - PC1++PC2++PC3 - end, - IncPtr=[ - #{<<"t">> => <<"set">>, - <<"p">> => ChainPath ++ [<<"parent">>], - <<"v">> => ParentHash - }, - #{<<"t">> => <<"set">>, - <<"p">> => ChainPath ++ [<<"height">>], - <<"v">> => MyHeight - } - |PCP ], - SyncPatch={PatchTxID, #{sig=>[], patch=>IncPtr}}, - { - settings:patch(SyncPatch, SetState), - [SyncPatch|Settings] - } - end, NewAddresses=maps:put(From, NewF, Addresses), Tx1=case GotGas of {_,0,_} -> tx:del_ext(<<"xc_gas">>, Tx); @@ -953,8 +1006,6 @@ try_process_outbound([{TxID, try_process(Rest, savefee(GotFee, Acc#{ - settings=>Set2, - new_settings=>SS2, table => NewAddresses, success=>[{TxID, Tx1}|Success], outbound=>[{TxID, OutTo}|Outbound], @@ -1228,27 +1279,31 @@ deposit(TxID, Address, Addresses0, #{ver:=2}=Tx, GasLimit, end, Addresses2, Changes), LToPatch=maps:get(Address, Addresses3), Addresses4=maps:put(Address, mbal:patch(LedgerPatches,LToPatch), Addresses3), - {Addresses4, EmitTxs, GasLeft, Acc2#{aalloc=>AAlloc2, log=>EmitLog++Logs}, - case maps:get("return",OpaqueState2,undefined) of + AddED=case maps:get("return",OpaqueState2,undefined) of <> when Int < 16#10000000000000000 -> - [{retval, Int}]; + [{<<"retval">>, Int}]; <> -> - [{retval, Bin}]; + [{<<"retval">>, Bin}]; RetVal when is_binary(RetVal) -> - [{retval, other}]; + [{<<"retval">>, <<"other">>}]; undefined -> case maps:get("revert",OpaqueState2,undefined) of <<16#08C379A0:32/big, 16#20:256/big, Len:256/big, Str:Len/binary,_/binary>> when 32>=Len -> - [{revert, Str}]; + [{<<"revert">>, Str}]; Revert when is_binary(Revert) -> - [{revert, other}]; + [{<<"revert">>, <<"other">>}]; undefined -> [] end - end + end, + {Addresses4, + EmitTxs, + GasLeft, + Acc2#{aalloc=>AAlloc2, log=>EmitLog++Logs}, + AddED } end. @@ -1471,12 +1526,20 @@ return_gas({GCur, GAmount, _GRate}=_GasLeft, _Settings, Bal0) -> Bal0 end. -addrcheck(Addr) -> +addrcheck(Addr, Set, OC) -> case naddress:check(Addr) of {true, #{type:=public}} -> case address_db:lookup(Addr) of + {ok, Chain} when Chain==OC-> + {true, {chain, Chain}}; {ok, Chain} -> - {true, {chain, Chain}}; + Valid=maps:get(chains,Set,[]), + case lists:member(Chain,Valid) of + true -> + {true, {chain, Chain}}; + false -> + unroutable + end; _ -> unroutable end; diff --git a/apps/tpnode/src/genesis_easy.erl b/apps/tpnode/src/genesis_easy.erl index dc82ecf5..145c7376 100644 --- a/apps/tpnode/src/genesis_easy.erl +++ b/apps/tpnode/src/genesis_easy.erl @@ -5,7 +5,7 @@ wrfile(Filename, Data) -> file:write_file(Filename, io_lib:format("~p.~n",[Data])). make_example(ChainNo, NodesCnt) -> - PrivKeys=[{N,tpecdsa:generate_priv()} || N<- lists:seq(1,NodesCnt) ], + PrivKeys=[{N,tpecdsa:generate_priv(ed25519)} || N<- lists:seq(1,NodesCnt) ], PrivKeys2File=[ {N,hex:encode(Key)} || {N,Key} <- PrivKeys], wrfile("easy_chain"++(integer_to_list(ChainNo))++"_keys.txt", PrivKeys2File), PubKeysPatch=[ @@ -14,7 +14,7 @@ make_example(ChainNo, NodesCnt) -> [ #{<<"p">> => [<<"keys">>,CN], <<"t">> => <<"set">>, - <<"v">> =>tpecdsa:calc_pub(Key,true)}, + <<"v">> =>tpecdsa:calc_pub(Key)}, #{<<"p">> => [<<"nodechain">>,CN],<<"t">> => <<"set">>,<<"v">> => ChainNo} ] end diff --git a/apps/tpnode/src/settings.erl b/apps/tpnode/src/settings.erl index 901be10c..72cc2d1b 100644 --- a/apps/tpnode/src/settings.erl +++ b/apps/tpnode/src/settings.erl @@ -1,69 +1,71 @@ -module(settings). +-include("include/tplog.hrl"). -export([new/0, set/3, patch/2, mp/1, dmp/1, get/2]). --export([sign/2, verify/1, verify/2, get_patches/1, get_patches/2]). +-export([get_patches/1, get_patches/2]). +%-export([sign/2, verify/1, verify/2]). -export([make_meta/2, clean_meta/1]). -sign(Patch, PrivKey) when is_list(Patch) -> - BinPatch=mp(Patch), - sign(#{patch=>BinPatch, sig=>[]}, PrivKey); -sign(Patch, PrivKey) when is_binary(Patch) -> - sign(#{patch=>Patch, sig=>[]}, PrivKey); - -sign(#{patch:=LPatch}=Patch, PrivKey) -> - BPatch=if is_list(LPatch) -> mp(LPatch); - is_binary(LPatch) -> LPatch - end, - Sig=bsig:signhash( - crypto:hash(sha256, BPatch), - [{timestamp, os:system_time(millisecond)}], - PrivKey), - #{ patch=>BPatch, - sig => [Sig|maps:get(sig, Patch, [])] - }. - -verify(#{patch:=LPatch, sig:=HSig}=Patch, VerFun) -> - BinPatch=if is_list(LPatch) -> mp(LPatch); - is_binary(LPatch) -> LPatch - end, - {Valid, Invalid}=bsig:checksig(crypto:hash(sha256, BinPatch), HSig), - case length(Valid) of - 0 -> - bad_sig; - N when N>0 -> - Map=lists:foldl(%make signatures unique - fun(#{extra:=ED}=P,Acc) -> - case proplists:get_value(pubkey,ED) of - PK when is_binary(PK) -> - maps:put(PK,P,Acc); - _ -> - Acc - end - end, #{}, Valid), - ValidSig=if VerFun==undefined -> - maps:values(Map); - is_function(VerFun) -> - maps:fold( - fun(K,V,Acc) -> - case VerFun(K) of - true -> - [V|Acc]; - false -> - Acc - end - end, [], Map) - end, - {ok, Patch#{ - sigverify=>#{ - valid=>ValidSig, - invalid=>Invalid - } - } - } - end. - -verify(#{patch:=_, sig:=_}=Patch) -> - verify(Patch, undefined). +%sign(Patch, PrivKey) when is_list(Patch) -> +% BinPatch=mp(Patch), +% sign(#{patch=>BinPatch, sig=>[]}, PrivKey); +%sign(Patch, PrivKey) when is_binary(Patch) -> +% sign(#{patch=>Patch, sig=>[]}, PrivKey); +% +%sign(#{patch:=LPatch}=Patch, PrivKey) -> +% BPatch=if is_list(LPatch) -> mp(LPatch); +% is_binary(LPatch) -> LPatch +% end, +% Sig=bsig:signhash( +% crypto:hash(sha256, BPatch), +% [{timestamp, os:system_time(millisecond)}], +% PrivKey), +% #{ patch=>BPatch, +% sig => [Sig|maps:get(sig, Patch, [])] +% }. +% +%verify(#{patch:=LPatch, sig:=HSig}=Patch, VerFun) -> +% BinPatch=if is_list(LPatch) -> mp(LPatch); +% is_binary(LPatch) -> LPatch +% end, +% {Valid, Invalid}=bsig:checksig(crypto:hash(sha256, BinPatch), HSig), +% case length(Valid) of +% 0 -> +% bad_sig; +% N when N>0 -> +% Map=lists:foldl(%make signatures unique +% fun(#{extra:=ED}=P,Acc) -> +% case proplists:get_value(pubkey,ED) of +% PK when is_binary(PK) -> +% maps:put(PK,P,Acc); +% _ -> +% Acc +% end +% end, #{}, Valid), +% ValidSig=if VerFun==undefined -> +% maps:values(Map); +% is_function(VerFun) -> +% maps:fold( +% fun(K,V,Acc) -> +% case VerFun(K) of +% true -> +% [V|Acc]; +% false -> +% Acc +% end +% end, [], Map) +% end, +% {ok, Patch#{ +% sigverify=>#{ +% valid=>ValidSig, +% invalid=>Invalid +% } +% } +% } +% end. +% +%verify(#{patch:=_, sig:=_}=Patch) -> +% verify(Patch, undefined). new() -> #{}. @@ -274,16 +276,22 @@ patch1([#{<<"t">>:=Action, <<"p">>:=K, <<"v">>:=V}|Settings], M) -> patch1(Settings, M1). %txv2 -patch({_TxID, #{patches:=Patch, sig:=Sigs}}, M) -> - patch(#{patch=>Patch, sig=>Sigs}, M); +patch(#{patches:=Patch, sig:=_Sigs}, M) -> + patch1(Patch, M); + +%txv2 +patch({_TxID, #{patches:=Patch, sig:=_Sigs}}, M) -> + patch1(Patch, M); %tvx1 -patch({_TxID, #{patch:=Patch, sig:=Sigs}}, M) -> - patch(#{patch=>Patch, sig=>Sigs}, M); +patch({_TxID, #{patch:=Patch, sig:=Sigs}}=E, M) -> + ?LOG_NOTICE("deprecated v1 patch ~p", [E]), + patch(#{patch=>Patch, sig=>Sigs}, M); %txv1 -patch(#{patch:=Patch}, M) -> - patch(Patch, M); +patch(#{patch:=Patch}=E, M) -> + ?LOG_NOTICE("deprecated v1 patch ~p", [E]), + patch(Patch, M); %naked patch(Changes, M) when is_list(Changes) -> diff --git a/apps/tpnode/src/tpnode_http.erl b/apps/tpnode/src/tpnode_http.erl index 855fc54f..a3ba3733 100644 --- a/apps/tpnode/src/tpnode_http.erl +++ b/apps/tpnode/src/tpnode_http.erl @@ -13,6 +13,8 @@ get_http_conn_type() -> {'_', [ {"/api/ws", tpnode_ws, []}, {"/api/[...]", apixiom, {tpnode_httpapi, #{}}}, + {"/xchain/ws", xchain_server, []}, + {"/xchain/api/[...]", apixiom, {xchain_api, #{}}}, {"/", cowboy_static, {priv_file, tpnode, "index.html"}}, {"/[...]", cowboy_static, {dir, "public", diff --git a/apps/tpnode/src/tpnode_httpapi.erl b/apps/tpnode/src/tpnode_httpapi.erl index cb07156f..5067a70e 100644 --- a/apps/tpnode/src/tpnode_httpapi.erl +++ b/apps/tpnode/src/tpnode_httpapi.erl @@ -215,7 +215,7 @@ h(<<"GET">>, [<<"node">>, <<"tpicpeers">>], _Req) -> h(<<"GET">>, [<<"node">>, <<"chainstate">>], _Req) -> R=maps:fold( fun({H,B1,B2,Tmp},Cnt,A) -> - [[H,hex:encode(B1),hex:encode(B2),Tmp,Cnt]|A] + [[H,hex:encode(B1),hex:encode(B2),Tmp,length(Cnt),Cnt]|A] end, [], blockchain_sync:chainstate()), diff --git a/apps/tpnode/src/tx.erl b/apps/tpnode/src/tx.erl index 3d89d155..830a1f42 100644 --- a/apps/tpnode/src/tx.erl +++ b/apps/tpnode/src/tx.erl @@ -585,8 +585,9 @@ sign(#{kind:=_Kind, Sig=bsig:signhash(Body,[],PrivKey), Tx#{sig=>[Sig|PS]}; -sign(Any, PrivKey) -> - tx1:sign(Any, PrivKey). +sign(Any, _PrivKey) -> + throw({not_a_tx,Any}). + %tx1:sign(Any, PrivKey). -type tx() :: tx2() | tx1(). @@ -714,18 +715,25 @@ verify(#{ sig:=LSigs, ver:=2 }=Tx, Opts) -> - CheckFun=case lists:keyfind(settings,1,Opts) of - {_,Sets0} -> + NCK=lists:member(nocheck_keys, Opts), + CheckFun=case {NCK,lists:keyfind(settings,1,Opts)} of + {true,_} -> + fun(_PubKey,_) -> + true + end; + {false, {_,Sets0}} -> fun(PubKey,_) -> chainsettings:is_our_node(PubKey, Sets0) =/= false end; - false -> + {false, false} -> fun(PubKey,_) -> chainsettings:is_our_node(PubKey) =/= false end end, Res=bsig:checksig(Body, LSigs, CheckFun), case Res of + {[], _} when NCK==true -> + bad_sig; {[], _} -> Sets=case lists:keyfind(settings,1,Opts) of {_,Sets1} -> @@ -764,6 +772,16 @@ verify(#{ _ -> bad_sig end; + {Valid, Invalid} when length(Valid)>0 andalso NCK -> + {ok, Tx#{ + sigverify=>#{ + valid=>length(Valid), + invalid=>Invalid, + source=>unverified, + pubkeys=>bsig:extract_pubkeys(Valid) + } + } + }; {Valid, Invalid} when length(Valid)>0 -> {ok, Tx#{ sigverify=>#{ @@ -787,8 +805,9 @@ verify(Bin, Opts) when is_binary(Bin) -> end; -verify(Struct, Opts) -> - tx1:verify(Struct, Opts). +verify(Struct, _Opts) -> + throw({invalid_tx, Struct}). + %tx1:verify(Struct, Opts). -spec pack(tx()) -> binary(). @@ -838,7 +857,8 @@ pack(#{ ver:=2, ]); pack(Any, _) -> - tx1:pack(Any). + throw({invalid_tx, Any}). + %tx1:pack(Any). complete_tx(BinTx,Comp) when is_binary(BinTx) -> @@ -872,16 +892,8 @@ unpack(BinTx,Opts) when is_binary(BinTx), is_list(Opts) -> }); #{<<"ver">>:=2, sig:=Sign, <<"body">>:=TxBody} -> unpack_generic(Trusted, Tx0, TxBody, Sign); - #{<<"ver">>:=2, <<"sig">>:=Sign, <<"body">>:=TxBody, <<"inv">>:=Inv} -> - unpack_body( #{ - ver=>2, - sig=>Sign, - body=>TxBody, - inv=>Inv - }); - #{<<"ver">>:=2, <<"sig">>:=Sign, <<"body">>:=TxBody} -> - unpack_generic(Trusted, Tx0, TxBody, Sign); _ -> + ?LOG_INFO("FIXME isTXv1: ~p", [Tx0]), tx1:unpack_mp(Tx0) end. diff --git a/apps/tpnode/src/txstatus.erl b/apps/tpnode/src/txstatus.erl index f70bc29d..be35446a 100644 --- a/apps/tpnode/src/txstatus.erl +++ b/apps/tpnode/src/txstatus.erl @@ -133,13 +133,13 @@ jsonfy1({true,#{address:=Addr}}) -> address=>naddress:encode(Addr) }; -jsonfy1({true,#{retval:=RV}}) when is_integer(RV)-> +jsonfy1({true,#{<<"retval">>:=RV}}) when is_integer(RV)-> #{ok=>true, res=>ok, retval=>RV }; -jsonfy1({true,#{retval:=RV}}) when is_binary(RV)-> +jsonfy1({true,#{<<"retval">>:=RV}}) when is_binary(RV)-> #{ok=>true, res=>ok, retval=>list_to_binary(["0x,",hex:encode(RV)]) diff --git a/apps/tpnode/src/xchain_client.erl b/apps/tpnode/src/xchain_client.erl index 3b88a161..0cd99347 100644 --- a/apps/tpnode/src/xchain_client.erl +++ b/apps/tpnode/src/xchain_client.erl @@ -12,7 +12,7 @@ %% API Function Exports %% ------------------------------------------------------------------ --export([start_link/1]). +-export([start_link/1,init_subscribes/1]). %% ------------------------------------------------------------------ %% gen_server Function Exports @@ -35,9 +35,10 @@ start_link(Options) -> init(_Args) -> State = #{ - subs => init_subscribes(#{}), + %subs => init_subscribes(#{}), + subs => #{}, chain => blockchain:chain(), - connect_timer => erlang:send_after(3 * 1000, self(), make_connections) + connect_timer => erlang:send_after(5 * 1000, self(), make_connections) }, code:ensure_loaded(xchain_client_handler), {ok, State}. @@ -113,7 +114,8 @@ handle_info({wrk_down, ConnPid, Reason}, #{subs:=Subs} = State) -> handle_info(make_connections, #{connect_timer:=Timer, subs:=Subs} = State) -> catch erlang:cancel_timer(Timer), - NewSubs = make_connections(Subs), + Subs1 = init_subscribes(Subs), + NewSubs = make_connections(Subs1), {noreply, State#{ subs => NewSubs, @@ -176,8 +178,6 @@ make_connections(Subs) -> Subs ). - - add_sub(#{address:=IP,port:=Port}=Subscribe, Subs) -> try Key = {IP,Port}, @@ -240,19 +240,92 @@ change_settings_handler(#{chain:=Chain, subs:=Subs} = State) -> end. init_subscribes(Subs) -> + CS=case ets:info(blockchain) of + undefined -> + false; + _ -> + true + end, Config = application:get_env(tpnode, crosschain, #{}), - ConnectIpsList = maps:get(connect, Config, []), - lists:foldl( - fun({Ip, Port}, Acc) when is_integer(Port) -> - Sub = #{ - address => Ip, - port => Port - }, - add_sub(Sub, Acc); - (Invalid, Acc) -> - ?LOG_ERROR("xhcain client got invalid crosschain connect term: ~p", Invalid), - Acc - end, Subs, ConnectIpsList). + case maps:get(connect, Config, undefined) of + undefined -> + MyCfg=if CS==false -> + #{}; + CS==true -> + CfgPath=[<<"current">>, <<"xchain">>, nodekey:node_name()], + chainsettings:by_path(CfgPath) + end, + case maps:get(<<"connect">>,MyCfg,#{}) of + Nodes2Connect when is_list(Nodes2Connect) -> + S1=lists:foldl( + fun(NodeName,A) -> + C=chainsettings:contacts(NodeName,[<<"xchain">>,<<"xchain+tls">>]), + if is_list(C) -> + lists:foldl( + fun(ConnTo,Acc) -> + %uri_string:parse(<<"xchain://user:pw@10.3.252.69:1080/as/er.txt?x=1#s123">>). + URI=#{scheme:=S,host:=H,port:=P}=uri_string:parse(ConnTo), + Parts=binary:split( + maps:get( query, URI, <<>>), + <<"&">>, + [global]), + Param=[ case binary:split(L,<<"=">>) of + [A1,B1] -> {A1,B1}; + [A1] -> A1 + end || L <- Parts ]--[<<>>], + case S of + <<"xchain">> -> + add_sub( #{ url=>ConnTo, + scheme=>S, + address => binary_to_list(H), + port => P, + param => Param, + new => true + },Acc); + <<"xchain+tls">> -> %not ready yet, so ignore + Acc; + _ -> + Acc + end + end, + A, C); + C==#{} -> + A; + true -> + ?LOG_ERROR("Can't parse node ~p contacts ~p",[NodeName,C]), + A + end + end, + Subs, + Nodes2Connect), + maps:fold( + fun(K, #{new:=_}=V, Acc) -> + maps:put(K,maps:remove(new,V),Acc); + (K, #{worker:=_}=V, Acc) -> + maps:put(K,V,Acc); + (_K, _Sub, Acc) -> + Acc + end, #{}, S1); + + #{} -> + Subs; + Any -> + ?LOG_ERROR("Can't parse connect ~p",[Any]), + Subs + end; + ConnectIpsList -> + lists:foldl( + fun({Ip, Port}, Acc) when is_integer(Port) -> + Sub = #{ + address => Ip, + port => Port + }, + add_sub(Sub, Acc); + (Invalid, Acc) -> + ?LOG_ERROR("xhcain client got invalid crosschain connect term: ~p", Invalid), + Acc + end, Subs, ConnectIpsList) + end. update_sub(Fun, GunPid, Subs) -> case find_sub_by_pid_and_ref(GunPid, Subs) of diff --git a/apps/tpnode/src/xchain_client_worker.erl b/apps/tpnode/src/xchain_client_worker.erl index 784d24a3..515da9c5 100644 --- a/apps/tpnode/src/xchain_client_worker.erl +++ b/apps/tpnode/src/xchain_client_worker.erl @@ -58,7 +58,7 @@ run(#{parent:=Parent, address:=Ip, port:=Port} = Sub, GetFun) -> end, Proto=case sync_get_decode(Pid, "/xchain/api/compat.mp") of {200, _, #{<<"ok">>:=true,<<"version">>:=Ver}} -> Ver; - {404, _, _} -> 0; + {404, _, _} -> throw('xchain_protocol_does_not_supported'); _ -> 0 end, {[<<"websocket">>],UpgradeHdrs}=upgrade(Pid,Proto), @@ -149,7 +149,7 @@ ws_mode(Pid, #{parent:=Parent, proto:=Proto}=Sub, GetFun) -> Cmd = xchain:pack(Payload, Proto), gun:ws_send(Pid, {binary, Cmd}), ?MODULE:ws_mode(Pid, Sub, GetFun); - {gun_ws, Pid, {binary, Bin}} -> + {gun_ws, Pid, _Ref, {binary, Bin}} -> Cmd = xchain:unpack(Bin, Proto), ?LOG_DEBUG("XChain client got ~p",[Cmd]), Sub1=xchain_client_handler:handle_xchain(Cmd, Pid, Sub), diff --git a/rebar.config b/rebar.config index 10c19d5b..9e07e445 100644 --- a/rebar.config +++ b/rebar.config @@ -70,7 +70,7 @@ {relx, [ - {release, { thepower, "0.13.14" }, [tpnode, + {release, { thepower, "0.14.1" }, [tpnode, sasl, runtime_tools ]}, diff --git a/test/basic_SUITE.erl b/test/basic_SUITE.erl index dc0b28a0..c1fd20d1 100644 --- a/test/basic_SUITE.erl +++ b/test/basic_SUITE.erl @@ -31,6 +31,7 @@ all() -> register_wallet_test, patch_gasprice_test, %smartcontract_test, + %smartcontract2_test, evm_test, check_blocks_test, discovery_got_announce_test, @@ -94,7 +95,7 @@ save_bckups() -> end, lists:foreach(SaveBckupForNode, get_testnet_nodenames()), ok. - + %%get_node_cmd(Name) when is_list(Name) -> @@ -291,8 +292,8 @@ discovery_ssl_test(_Config) -> Ips = maps:get(ip, AddrInfo, []), ?assertEqual(true, lists:member(Host, Hosts)), ?assertEqual(true, lists:member(Ip, Ips)). - - + + discovery_got_announce_test(_Config) -> @@ -523,7 +524,7 @@ dump_testnet_state() -> erlang:spawn(?MODULE, dump_node_state, [self(), NodeName]) || NodeName <- get_testnet_nodenames() ], - + wait_for_dumpers(Pids), ok. % ----------------------------------------------------------------------------- @@ -552,7 +553,7 @@ wait_for_dumpers(Pids, StatesAcc) -> wait_for_dumpers(Pids, StatesAcc); _ -> logger("------ testnet states data ------"), - + maps:filter( fun (NodeName, NodeStates) -> @@ -564,7 +565,7 @@ wait_for_dumpers(Pids, StatesAcc) -> end, StatesAcc ), - + logger("------ end of data ------"), ok end @@ -679,6 +680,113 @@ evm_test(_Config) -> % ?assertMatch(#{<<"res">> := <<"ok">>}, StatusDJ), ok. +smartcontract2_test(_Config) -> + {ok,Addr}=application:get_env(tptest,endless_addr), + {ok,Priv}=application:get_env(tptest,endless_addr_pk), + ?assertMatch(true, is_binary(Addr)), + ?assertMatch(true, is_binary(Priv)), + + {ok, Code}=file:read_file("../examples/testcontract_emit.ec"), + + DeployTx=tx:pack( + tx:sign( + tx:construct_tx( + #{ver=>2, + kind=>deploy, + from=>Addr, + seq=>os:system_time(millisecond), + t=>os:system_time(millisecond), + payload=>[#{purpose=>gas, amount=>50000, cur=><<"FTT">>}], + call=>#{function=>"init",args=>[1024]}, + txext=>#{ "code"=> Code,"vm" => "erltest"}} + ),Priv)), + + #{<<"txid">>:=TxID1} = api_post_transaction(DeployTx), + {ok, Status1, _} = api_get_tx_status(TxID1), + ?assertMatch(#{<<"res">> := <<"ok">>}, Status1), + + GenTx=tx:pack( + tx:sign( + tx:construct_tx( + #{ver=>2, + kind=>generic, + to=>Addr, + from=>Addr, + seq=>os:system_time(millisecond), + t=>os:system_time(millisecond), + payload=>[#{purpose=>gas, amount=>50000, cur=><<"FTT">>}], + call=>#{function=>"notify",args=>[1024]} + } + ),Priv)), + + #{<<"txid">>:=TxID2} = api_post_transaction(GenTx), + {ok, Status2, _} = api_get_tx_status(TxID2), + ?assertMatch(#{<<"res">> := <<"ok">>}, Status2), + + DJTx=tx:pack( + tx:sign( + tx:construct_tx( + #{ver=>2, + kind=>generic, + to=>Addr, + from=>Addr, + seq=>os:system_time(millisecond), + t=>os:system_time(millisecond), + payload=>[#{purpose=>gas, amount=>50000, cur=><<"FTT">>}], + call=>#{function=>"delayjob",args=>[1024]} + }),Priv)), + + #{<<"txid">>:=TxID3} = api_post_transaction(DJTx), + {ok, #{<<"block">>:=Blkid3}=Status3, _} = api_get_tx_status(TxID3), + ?assertMatch(#{<<"res">> := <<"ok">>}, Status3), + + Emit=tx:pack( + tx:sign( + tx:construct_tx( + #{ver=>2, + kind=>generic, + to=>Addr, + from=>Addr, + seq=>os:system_time(millisecond), + t=>os:system_time(millisecond), + payload=>[#{purpose=>gas, amount=>50000, cur=><<"FTT">>}], + call=>#{function=>"emit",args=>[1024]} + }),Priv)), + + #{<<"txid">>:=TxID4} = api_post_transaction(Emit), + {ok, Status4, _} = api_get_tx_status(TxID4), + ?assertMatch(#{<<"res">> := <<"ok">>}, Status4), + + BadResp=tx:pack( + tx:sign( + tx:construct_tx( + #{ver=>2, + kind=>generic, + to=>Addr, + from=>Addr, + seq=>os:system_time(millisecond), + t=>os:system_time(millisecond), + payload=>[#{purpose=>gas, amount=>50000, cur=><<"FTT">>}], + call=>#{function=>"badnotify",args=>[1024]} + }),Priv)), + + #{<<"txid">>:=TxID5} = api_post_transaction(BadResp), + {ok, Status5, _} = api_get_tx_status(TxID5), + ?assertMatch(#{<<"res">> := <<"ok">>}, Status5), + + #{etxs:=[{DJTxID,_}|_]}=Block3=tpapi:get_fullblock(Blkid3,get_base_url()), + + io:format("Block3 ~p~n",[Block3]), + io:format("Have to wait for DJ tx ~p~n",[DJTxID]), + ?assertMatch(#{etxs:=[{<<"8001400004",_/binary>>,#{not_before:=_}}]},Block3), + + {ok, StatusDJ, _} = api_get_tx_status(DJTxID, 65), + io:format("DJ tx status ~p~n",[StatusDJ]), + ?assertMatch(#{<<"res">> := <<"ok">>}, StatusDJ), + ok. + + +% %smartcontract_test(_Config) -> % {ok,Addr}=application:get_env(tptest,endless_addr), % {ok,Priv}=application:get_env(tptest,endless_addr_pk), @@ -802,25 +910,27 @@ test_blocks_verify(_, <<0,0,0,0,0,0,0,0>>, C) -> C; test_blocks_verify(Reader, Pos, C) -> - Blk=gen_server:call(Reader,{get_block,Pos}), - if(is_map(Blk)) -> - ok; - true -> - throw({noblock,Pos}) - end, - {true,_}=block:verify(Blk), - case block:verify(block:unpack(block:pack(Blk))) of - false -> - io:format("bad block ~p (depth ~w)~n",[Pos,C]), - throw('BB'); - {true,_} -> - case Blk of - #{header:=#{parent:=PBlk}} -> - test_blocks_verify(Reader, PBlk, C+1); - _ -> - C+1 - end - end. + Blk=gen_server:call(Reader,{get_block,Pos}), + case Blk of + #{header:=#{height:=0}} -> + C; + #{header:=#{height:=_},hash:=_} -> + {true,_}=block:verify(Blk), + case block:verify(block:unpack(block:pack(Blk))) of + false -> + io:format("bad block ~p (depth ~w)~n",[Pos,C]), + throw('BB'); + {true,_} -> + case Blk of + #{header:=#{parent:=PBlk}} -> + test_blocks_verify(Reader, PBlk, C+1); + _ -> + C+1 + end + end; + _ -> + throw({noblock,Pos}) + end. crashme_test(_Config) -> ?assertMatch(crashme,ok). @@ -837,7 +947,7 @@ transaction_test(_Config) -> rpc:call(get_node(get_default_nodename()), erlang, whereis, [txpool]), C4N1NodePrivKey = rpc:call(get_node(get_default_nodename()), nodekey, get_priv, []), - + PatchTx = tx:sign( tx:construct_tx( #{kind=>patch, @@ -851,7 +961,7 @@ transaction_test(_Config) -> <<"v">>=>true}] } ), C4N1NodePrivKey), - + {ok, PatchTxId} = gen_server:call(TxpoolPidC4N1, {new_tx, PatchTx}), logger("PatchTxId: ~p~n", [PatchTxId]), {ok, _} = wait_for_tx(PatchTxId, get_node(get_default_nodename())), @@ -990,7 +1100,7 @@ tpiccall(TPIC, Handler, Object, Atoms) -> % ] % ), % gen_server:call(Pid, '_flush'), -% +% % Hash2=rpc:call(get_node(get_default_nodename()),ledger,check,[[]]), % Hash2=rpc:call(get_node(get_default_nodename()),ledger,check,[[]]), % @@ -1009,7 +1119,7 @@ tpiccall(TPIC, Handler, Object, Atoms) -> % ?assertEqual(Hash1,Hash2), % gen_server:cast(Pid, terminate), % done. -% +% % %inst_sync_wait_more(A) -> % receive @@ -1040,7 +1150,7 @@ tpiccall(TPIC, Handler, Object, Atoms) -> logger(Format) when is_list(Format) -> logger(Format, []). - + logger(Format, Args) when is_list(Format), is_list(Args) -> utils:logger(Format, Args). diff --git a/test/mkblock_cont_tests.erl b/test/mkblock_cont_tests.erl index 4ccfe9c9..6ff534b3 100644 --- a/test/mkblock_cont_tests.erl +++ b/test/mkblock_cont_tests.erl @@ -26,39 +26,7 @@ allocport() -> gen_tcp:close(S), CPort. -extcontract_template(OurChain, TxList, Ledger, CheckFun, Workers) -> - Servers=case whereis(tpnode_vmsrv) of - undefined -> - Port=allocport(), - application:ensure_all_started(ranch), - {ok, Pid1} = tpnode_vmsrv:start_link(), - {ok, Pid2} = ranch_listener_sup:start_link( - {vm_listener,Port}, - ranch_tcp, - #{ - connection_type => supervisor, - socket_opts => [{port,Port}] - }, - tpnode_vmproto,[]), - timer:sleep(300), - [fun()->gen_server:stop(Pid1) end, - fun()->exit(Pid2,normal) end - | [ - begin - SPid=vm_erltest:run("127.0.0.1",Port), - fun()->SPid ! stop end - end || _ <- lists:seq(1,Workers) ] - ]; - _ -> - VMPort=application:get_env(tpnode,vmport,50050), - [ - begin - SPid=vm_erltest:run("127.0.0.1",VMPort), - fun()->SPid ! stop end - end || _ <- lists:seq(1,Workers) ] - end, - timer:sleep(200), - try +extcontract_template(OurChain, TxList, Ledger, CheckFun, _Workers) -> Test=fun(LedgerPID) -> GetSettings=fun(mychain) -> OurChain; (settings) -> @@ -156,14 +124,14 @@ extcontract_template(OurChain, TxList, Ledger, CheckFun, Workers) -> [{ledger_pid, LedgerPID}])) end, - mledger:deploy4test(Ledger, Test) - -after - lists:foreach( - fun(TermFun) -> - TermFun() - end, Servers) - end. + mledger:deploy4test(Ledger, Test). +% +%after +% lists:foreach( +% fun(TermFun) -> +% TermFun() +% end, Servers) +% end. %extcontract_baddeploy1_test() -> % OurChain=150, @@ -267,7 +235,7 @@ xchain_test_callingblock() -> GetSettings=fun(mychain) -> Chain2; (settings) -> #{ - chains => [1,Chain2], + chains => [Chain1,Chain2], keys => #{ <<"node1">> => crypto:hash(sha256, <<"node1">>), @@ -360,7 +328,39 @@ xchain_test_callingblock() -> mledger:deploy4test(Ledger, Test). - +xchain_test() -> + Chain1=1, + Pvt1= <<194, 124, 65, 109, 233, 236, 108, 24, 50, 151, 189, 216, 23, 42, 215, 220, 24, 240, + 248, 115, 150, 54, 239, 58, 218, 221, 145, 246, 158, 15, 210, 165>>, + Addr1=naddress:construct_public(1, Chain1, 1), + Addr2=naddress:construct_public(1, Chain1+10, 1), + TX1=tx:sign( + tx:construct_tx(#{ + ver=>2, + kind=>generic, + from=>Addr1, + to=>Addr2, + seq=>2, + t=>os:system_time(millisecond), + payload=>[ + #{purpose=>transfer, amount=>30, cur=><<"FTT">>} + #{purpose=>srcfee, amount=>28, cur=><<"TST">>} + ] + }), Pvt1), + TestFun=fun(#{block:=Block, + failed:=Failed}) -> + io:format("Block ~p~n",[Block]), + io:format("Failed ~p~n",[Failed]) + end, + Ledger1=[ + {Addr1, + #{amount => #{ <<"FTT">> => 10, <<"SK">> => 3, <<"TST">> => 28 }} + } + ], + TxL=[ + {<<"1test">>, maps:put(sigverify,#{valid=>1},TX1)} + ], + extcontract_template(Chain1, TxL, Ledger1, TestFun, 1). %xchain_test() -> % Chain1=1, diff --git a/test/mkblock_tests.erl b/test/mkblock_tests.erl index c8aacfe3..9fea1357 100644 --- a/test/mkblock_tests.erl +++ b/test/mkblock_tests.erl @@ -620,7 +620,7 @@ mkblock_tx2_test() -> OurChain; (settings) -> #{ - chains => [0, 1], + chains => [0, 1, OurChain+2], chain => #{0 => #{blocktime => 5, minsig => 2, <<"allowempty">> => 0}, @@ -886,7 +886,7 @@ mkblock_test() -> OurChain; (settings) -> #{ - chains => [0, 1], + chains => [0, 1, OurChain, OurChain+2], chain => #{0 => #{blocktime => 5, minsig => 2, <<"allowempty">> => 0}, @@ -985,6 +985,20 @@ mkblock_test() -> seq=>4, t=>os:system_time(millisecond) }), Pvt1), + TX2f=tx:sign( + tx:construct_tx( + #{ + ver=>2, + kind=>generic, + from=>naddress:construct_public(SG, OurChain, 3), + to=>naddress:construct_public(1, OurChain+3, 1), + payload=>[ + #{purpose=>transfer, amount=>9, cur=><<"FTT">>}, + #{purpose=>srcfee, amount=>1, cur=><<"FTT">> } + ], + seq=>4, + t=>os:system_time(millisecond) + }), Pvt1), TX3=tx:sign( tx:construct_tx( #{ @@ -1087,6 +1101,7 @@ mkblock_test() -> {<<"1interchain">>, maps:put(sigverify,#{valid=>1},TX0)}, {<<"2invalid">>, maps:put(sigverify,#{valid=>1},TX1)}, {<<"3crosschain">>, maps:put(sigverify,#{valid=>1},TX2)}, + {<<"3.1badcross">>, maps:put(sigverify,#{valid=>1},TX2f)}, {<<"4crosschain">>, maps:put(sigverify,#{valid=>1},TX3)}, {<<"5nosk">>, maps:put(sigverify,#{valid=>1},TX4)}, {<<"6sklim">>, maps:put(sigverify,#{valid=>1},TX5)}, @@ -1109,6 +1124,7 @@ mkblock_test() -> [ ?assertMatch([{<<"2invalid">>, insufficient_fund}, + {<<"3.1badcross">>,bad_src_or_dst_addr}, {<<"5nosk">>, no_sk}, {<<"6sklim">>, sk_limit}, {<<"8nofee">>, {insufficient_fee, 2}}, @@ -1243,17 +1259,29 @@ xchain_test() -> ParentHash=crypto:hash(sha256, <<"parent">>), SG=3, + TX1a=tx:sign( + tx:upgrade( + #{ + from=>naddress:construct_public(SG, OurChain, 3), + to=>naddress:construct_public(SG, OurChain, 3), + amount=>0, + cur=><<"FTT">>, + extradata=>jsx:encode(#{ fee=>1, feecur=><<"FTT">> }), + seq=>3, + timestamp=>os:system_time(millisecond)-1 + }), Pvt1), + TX1=tx:sign( - tx:upgrade( + tx:upgrade( #{ - from=>naddress:construct_public(SG, OurChain, 3), - to=>naddress:construct_public(1, OurChain+1, 1), - amount=>9, - cur=><<"FTT">>, - extradata=>jsx:encode(#{ fee=>1, feecur=><<"FTT">> }), - seq=>4, - timestamp=>os:system_time(millisecond) - }), Pvt1), + from=>naddress:construct_public(SG, OurChain, 3), + to=>naddress:construct_public(1, OurChain+1, 1), + amount=>9, + cur=><<"FTT">>, + extradata=>jsx:encode(#{ fee=>1, feecur=><<"FTT">> }), + seq=>4, + timestamp=>os:system_time(millisecond) + }), Pvt1), TX2=tx:sign( tx:construct_tx( #{ @@ -1271,6 +1299,7 @@ xchain_test() -> #{block:=Block1, failed:=Failed1}=generate_block:generate_block( [ + {<<"tx0">>, maps:put(sigverify,#{valid=>1},TX1a)}, {<<"tx1">>, maps:put(sigverify,#{valid=>1},TX1)} ], {1, ParentHash}, @@ -1280,7 +1309,7 @@ xchain_test() -> Success1=proplists:get_keys(maps:get(txs, Block1)), ?assertMatch([], lists:sort(Failed1)), - ?assertEqual([ <<"tx1">> ], lists:sort(Success1)), + ?assertEqual([ <<"tx0">>, <<"tx1">> ], lists:sort(Success1)), ?assertEqual([ <<"tx1">> ], proplists:get_keys(maps:get(tx_proof, Block1)) ), @@ -1307,11 +1336,6 @@ xchain_test() -> GetAddr, []), SignedBlock2=block:sign(Block2, C1N1), - FormatBS=fun(Block) -> - settings:patch( - maps:get(patch,proplists:get_value(<<"outch:6">>,maps:get(settings,Block))), - #{}) - end, #{hash:=OH1}=OBlk1=maps:get(OurChain+1, block:outward_mk(maps:get(outbound, SignedBlock1), SignedBlock1)), #{hash:=OH2}=OBlk2=maps:get(OurChain+1, block:outward_mk(maps:get(outbound, SignedBlock2), SignedBlock2)), HOH1=hex:encode(OH1), @@ -1362,20 +1386,43 @@ xchain_test() -> GetAddr, []), - FormatDBS=fun(Block) -> - settings:patch( - maps:get(patch,proplists:get_value(<<"syncch:5">>,maps:get(settings,Block))), - #{}) - end, - TT=proplists:get_value(<<"tx2">>,maps:get(txs,RBlock2)), - { - FormatBS(OBlk1), - maps:get(hash,OBlk1), - FormatBS(OBlk2), - FormatDBS(RBlock1), - FormatDBS(RBlock2), - TT - } + FormatBS=fun(Block) -> + settings:patch( + maps:get(patches,proplists:get_value(<<"outch:6">>,maps:get(settings,Block))), + #{}) + end, + + %FormatDBS=fun(Block) -> + % settings:patch( + % maps:get(patches,proplists:get_value(<<"syncch:5">>,maps:get(settings,Block))), + % #{}) + % end, + [ + ?assertMatch(#{},proplists:get_value(<<"tx2">>,maps:get(txs,RBlock2))), + + ?assertEqual( + <<0,0,0,0,0,0,0,0>>, + settings:get([<<"current">>,<<"outward">>,<<"ch:6">>,<<"pre_hash">>], + FormatBS(OBlk1) + ) + ), + + ?assertEqual( + maps:get(hash,OBlk1), + settings:get([<<"current">>,<<"outward">>,<<"ch:6">>,<<"pre_hash">>], + FormatBS(OBlk2) + ) + ), + ?assertEqual( + maps:get(hash,OBlk1), + settings:get([<<"current">>,<<"outward">>,<<"ch:6">>,<<"parent">>], + FormatBS(OBlk2)) + ) + ] + %{ + % settings:get([<<"current">>,<<"sync_status">>,<<"ch:5">>,<<"block">>], FormatDBS(RBlock1)), + % FormatDBS(RBlock2) + %} end, Ledger=[], mledger:deploy4test(Ledger, Test). diff --git a/test/settings_tests.erl b/test/settings_tests.erl index 62ee7a18..12160e3a 100644 --- a/test/settings_tests.erl +++ b/test/settings_tests.erl @@ -23,20 +23,23 @@ patch_sign_test() -> 62, 9, 86, 147, 15, 193, 9, 244, 229, 208, 76, 222, 83, 208>>, TestPriv2= <<183, 31, 13, 74, 198, 72, 211, 62, 196, 207, 92, 98, 28, 31, 136, 0, 127, 128, 189, 172, 129, 122, 6, 39, 221, 242, 157, 21, 164, 81, 236, 181>>, - Patch1=#{patch => - [#{p => [chain, 0, blocktime], t => set, v => 1}, - #{p => [chain, 0, <<"allowempty">>], t => set, v => 0}] - }, - Patch2=#{patch => - [#{p => [chain, 0, blocktime], t => set, v => 2}, - #{p => [chain, 0, <<"allowempty">>], t => set, v => 0}] - }, - TwoSig= settings:sign( - settings:sign(Patch1, TestPriv1), + Patch1=tx:construct_tx(#{ver=>2, kind=>patch, + patches => + [#{p => [chain, 0, blocktime], t => set, v => 1}, + #{p => [chain, 0, <<"allowempty">>], t => set, v => 0}] + }), + Patch2=tx:construct_tx(#{ver=>2, kind=>patch, + patches => + [#{p => [chain, 0, blocktime], t => set, v => 2}, + #{p => [chain, 0, <<"allowempty">>], t => set, v => 0}] + }), + TwoSig= tx:sign( + tx:sign(Patch1, TestPriv1), TestPriv2), RePack=tx:unpack(tx:pack(TwoSig)), + ?assertEqual(TwoSig#{txext=>#{}}, RePack), BadSig=maps:merge(TwoSig, Patch2), - ReSig=settings:sign( + ReSig=tx:sign( BadSig, TestPriv2), TstGenesis=settings:dmp(settings:mp([ @@ -54,27 +57,27 @@ patch_sign_test() -> ])), Genesis=settings:patch(TstGenesis, #{}), - Patched=settings:patch(settings:verify(RePack), Genesis), + Patched=settings:patch(tx:verify(RePack,[nocheck_keys]), Genesis), [ ?assertMatch({ok, #{ sigverify:=#{ invalid:=0, - valid:=[_, _] + pubkeys:=[_, _] }} - }, settings:verify(TwoSig)), %simple check + }, tx:verify(TwoSig,[nocheck_keys])), %simple check ?assertMatch({ok, #{ sigverify:=#{ invalid:=0, - valid:=[_, _] + pubkeys:=[_, _] }} - }, settings:verify(RePack)), %check after packing and unpacking - ?assertEqual(bad_sig, settings:verify(BadSig)), %broken patch + }, tx:verify(RePack,[nocheck_keys])), %check after packing and unpacking + ?assertEqual(bad_sig, tx:verify(BadSig,[nocheck_keys])), %broken patch ?assertMatch({ok, #{ sigverify:=#{ - invalid:=2, - valid:=[_] + invalid:=_, + pubkeys:=[_] }} - }, settings:verify(ReSig)), %resig broken patch + }, tx:verify(ReSig,[nocheck_keys])), %resig broken patch ?assertMatch([_|_], TstGenesis), ?assertMatch(#{}, Genesis), ?assertMatch(5, settings:get([chain, 0, blocktime], Genesis)), diff --git a/test/tx_tests.erl b/test/tx_tests.erl index 88c205f4..3e9dbbd2 100644 --- a/test/tx_tests.erl +++ b/test/tx_tests.erl @@ -125,13 +125,18 @@ deploy_test() -> PubKey=tpecdsa:calc_pub(Priv, true), From=(naddress:construct_public(0, 0, 1)), Test=fun(LedgerPID) -> - TestTx2=#{ from=>From, - deploy=><<"chainfee">>, - code=><<"code">>, - state=><<"state">>, - timestamp => os:system_time(millisecond), - seq=>1 - }, + TestTx2=tx:construct_tx( + #{ ver=>2, + kind=>deploy, + from=>From, + payload => [], + txext => #{ + "code" => <<"code">>, + "vm" => "chainfee" + }, + t=> os:system_time(millisecond), + seq=>1 + }), BinTx2=tx:sign(TestTx2, Priv), BinTx2r=tx:pack(tx:unpack(BinTx2)), {ok, CheckTx2}=tx:verify(BinTx2,[{ledger, LedgerPID}]),