From c5d1243271fca79fab65aff895182bc9e383a540 Mon Sep 17 00:00:00 2001 From: Kasper Ziemianek Date: Thu, 31 Oct 2024 11:02:27 +0100 Subject: [PATCH] `omni-executor` enclave registration (#3150) * attestation --- common/primitives/core/src/teebag/types.rs | 1 + tee-worker/omni-executor/Makefile | 8 +- tee-worker/omni-executor/docker-compose.yml | 1 + .../omni-executor.manifest.template | 2 + .../artifacts/rococo-omni-account.scale | Bin 23684 -> 31087 bytes .../parentchain/listener/Cargo.toml | 3 + .../parentchain/listener/src/event_handler.rs | 84 +++++-------- .../parentchain/listener/src/fetcher.rs | 5 +- .../parentchain/listener/src/lib.rs | 84 ++++++++++++- .../parentchain/listener/src/listener.rs | 1 + .../parentchain/listener/src/metadata.rs | 6 +- .../parentchain/listener/src/rpc_client.rs | 20 +++ .../listener/src/transaction_signer.rs | 118 ++++++++++++++++++ 13 files changed, 267 insertions(+), 66 deletions(-) create mode 100644 tee-worker/omni-executor/parentchain/listener/src/transaction_signer.rs diff --git a/common/primitives/core/src/teebag/types.rs b/common/primitives/core/src/teebag/types.rs index bf8b02edf5..ec65014c3b 100644 --- a/common/primitives/core/src/teebag/types.rs +++ b/common/primitives/core/src/teebag/types.rs @@ -72,6 +72,7 @@ pub enum WorkerType { #[default] Identity, BitAcross, + OmniExecutor, } #[derive(Encode, Decode, Clone, Copy, Default, PartialEq, Eq, RuntimeDebug, TypeInfo)] diff --git a/tee-worker/omni-executor/Makefile b/tee-worker/omni-executor/Makefile index 5c91358fef..cb27222bc3 100644 --- a/tee-worker/omni-executor/Makefile +++ b/tee-worker/omni-executor/Makefile @@ -23,7 +23,7 @@ endif # of the DEBUG setting is to control Gramine's loglevel. -include $(SELF_EXE).d # See also: .cargo/config.toml $(SELF_EXE): Cargo.toml - cargo build --release + cargo build --release --features=gramine-quote omni-executor.manifest: omni-executor.manifest.template gramine-manifest \ @@ -73,6 +73,6 @@ start-local: stop-local: docker compose down -.PHONY: get-omni-pallet-metadata -get-omni-pallet-metadata: - subxt metadata --url http://localhost:9944 --allow-insecure --pallets OmniAccount > parentchain/artifacts/rococo-omni-account.scale +.PHONY: get-pallet-metadata +get-pallet-metadata: + subxt metadata --url http://localhost:9944 --allow-insecure --pallets OmniAccount,Teebag > parentchain/artifacts/rococo-omni-account.scale diff --git a/tee-worker/omni-executor/docker-compose.yml b/tee-worker/omni-executor/docker-compose.yml index b3798d98ed..98c7367c10 100644 --- a/tee-worker/omni-executor/docker-compose.yml +++ b/tee-worker/omni-executor/docker-compose.yml @@ -7,6 +7,7 @@ services: - ethereum-node - litentry-node command: ["executor-worker", "ws://litentry-node:9944", "http://ethereum-node:8545"] + restart: always ethereum-node: image: ghcr.io/foundry-rs/foundry command: diff --git a/tee-worker/omni-executor/omni-executor.manifest.template b/tee-worker/omni-executor/omni-executor.manifest.template index 526945bbdc..19638e4dbf 100644 --- a/tee-worker/omni-executor/omni-executor.manifest.template +++ b/tee-worker/omni-executor/omni-executor.manifest.template @@ -44,6 +44,8 @@ sgx.trusted_files = [ # https://gramine.readthedocs.io/en/stable/manifest-syntax.html#number-of-threads sgx.max_threads = {{ '1' if env.get('EDMM', '0') == '1' else '64' }} +sgx.remote_attestation = "dcap" + # for easy demo setup loader.insecure__use_cmdline_argv = true loader.insecure__use_host_env = true \ No newline at end of file diff --git a/tee-worker/omni-executor/parentchain/artifacts/rococo-omni-account.scale b/tee-worker/omni-executor/parentchain/artifacts/rococo-omni-account.scale index 2c9a40ede9e70fec0581665a2586478eafec6683..5f18bed23feac0aeafcfc87eefaaa395047d16f2 100644 GIT binary patch delta 11143 zcmcIq4{Th;nV)a`9M;LYS(CNBaW?QAHpQmS#!h0#c1*BiZ(@TTo7jPbB)56q9oz4+ zyKnQ}TgT?8mPm;TQc#H|+<^|HPz4Dpa*zXbMF*#(YOX{FEl7AvSNO^VWg92 z2lSDqAvA@}Qd%m;aLLJx5^%f;Jrf9ce7lX5a6R9skz@)XS%O65k)@R=bt`osj} zFs;od3@u*d&g29k<%B%O!^=Z(ijOY;Iy}iAUf#I&3~X^X?x=0*sY%?AdNQ4ernDqG z!!Is>2%hF^R&=$TL3&D_R=mB&F=3o%(TktODdB&5mYgL-@tpILbA*(6u+>9e&5T<%#vWYo??DKohlzV+^CnV8ypidoLf*qy{BEpNXJD9(@yr8DpqO zJnBY9{&!`yLqYfDeF)})Bvl?OF*^M}jrU=n2&+#bKWXqH@3z3(OL=Gnw;t(C5 zjTVRQ;^(3;uDr9Th-_Y)5?(0q)M5gQjwWS^L#14Ke^IFgp;??k5kr)lF4(Vd=HyKF zr<`KTl-CzhL@ceA$>z?-oCMV1k&>DJd6c+Cxww!LX4dhD`9e^SZj(*wcv6}<-GWP) zJKrT7_$N8YAQ1^PX||2WtVAhAu@)MR8CeN4N+AVwTT?nq#4*Z7)0y!jZ1yn$b0m0i zVF#YDq3M|0`yq_Ey^;8)*4CDek<55PkKvf^BEb^N{1Uo)3c4Vm$ui5gU$TTIE_!d~dcr>p=yQ9R-0(N}Dokfl$iG&^Im;?}+x zGi`lBk73x2O2AOmyIeU}s?lPyQLjFyFDpP^Y&@!`CJZmAxyK@=@Fys;Vs1>zE0Pl+ z+$)VREE_c>EQ<LtVrFPIDB5IYzqg3zpQ34Bt5GlPh{+qMumn_@F|bizT1a!W;HS}Lx`g-4VkM2Dcy zg`!N0<6;*h(i-L5Sm`VlQxm7)AJ-5OE8vgek!Sq|-V$4}YfRNF)lFP7ww^%z*4fE7 zR@T(iD*H-#OM1TBH;{dQX#kf$+DIrLRTfA@a{0sp0cVkX0tOQrI!@MNEEN?w7{;Vz zI%n89iOruc3bk94Gtu#ko`_3S@JSY$M<-`?hz2JAOX*P3Wv`9Jw1CuEOPb-{>cR&+qfv+#7r4{lkXciBcyi8*hmHEN1mgZhM z9(?`*%xn^Z@la0>GWHJ|=;D}YG>DE#Q^&*!F)jHGqCWZ}`INtU>tXnuSFPG#^*JHS z+R5(`YA%yd^CmyKs;&n>0MWKB+te)xL;>epreJrFltZ!AZ_cy&O= z(MsT7tWxP(;C23b+6cVM9}tbA|A;@>eiM9qWoj9k)GU$f#aL-mLS%pWrhq2XyDH%S z{t}u(x)Hu!hiq)rN5~O z9~N`)t~nT^{eA~?f;&2dV9gm#ah|~QK3T;mG-JhQ$QVNV!AYBj><;@*^q8c;|Y!j z+kU{KuLTPzUPKRv&{>4(?q_4MaWvmvv`Lvy?!Nu_Sgw#m!b%ztZBa7`K7Ppn7Xtz) z$eK>&q!1?QvI`YY1YtYM9YC}+oRR?+!^R(NQ>2b2L|w(w0mh^Q#Ks?BIDI2EitspN z;e>RdeiGs&xupKxs747X784*4OJ{H@Xx~7ud?FA?bj)4lij+TxAFFqq2@Vc%CF= z>n!FI>Yg5#R-KT_h7ZnTF=iOUi8w)n6$YbuY{O8EY$6`sH;|gff@8c$sx0=FE9KyJ zxk{rBs=#7RDhp4Bn^Y~O9+pQlJ1pDPj4%hzHMJqmrd5H>+FcHac_cbnrc}WgE`)2z ztcvhe*v7F+lRC~~TE;?~*p@0$lbEDnq@v1lU?O20WAX6e;)5UUKblE9pqgN|D&RcOJiQ1X%^BvXVueTcVgSdfqDK`K>Q{Ky zOEWvw4QFxCfSLSQY3YoHXjrbLdTffN)MHGw%~|2^Cfkt9+HjR$m(vz2;Vzqc3`>Km zrpEP&31+6yltqH}J!l%K$)Q|Pf2U!}+AHxYPs(+X1zE8v(4bj&Q`iNU2QF z-9h98UTa zU(NyN*iU+@*a~P0;q>_gDyON;mePf0*C%7Rc%qJM>DgGkCx5pw*9U#h917)`y!l=0 zx$bDsV^QKtRgNnyz(z~pL5D7v_oadc1(xJi<(%8@Y{0y}Y9@^V!SNHPwi)j0H4+I# z7p9hQH$GXVoE2;5?!UMi%a6d-$U4iRI}s?H9@1u9S%rNuJk87r-1Nk+%q-NeVpUTP zkmLo$T}FBGYDr$&FXL~X{?R=w#_+l%Uf5Hmha9O<9_bNN!5Rbx7MWWMcPjWr_+@wA zyK#x#n;hwSy}2}9o|f)?P3<=2m%=z0e=|(Q%AY)>1R_(5b9@mbog7~X%NdJ*v3gy_ zNpVQP&7h@S(bO@DxwisqhRxT~~`OFV(5p)8HbqHj$K^Mw+s2iJG2*LYC)( zSIiaN(vtwIrIgPUhWlA8ZfT{1pUaDBMKR9_F+D=eYVtfjE9wjI5}bz%@CLjMm*EPK z7r3_OUU&&V>-ayf`3Bx}h$nCGPPibSb_dtN8~kXnd-)x6^LPgp!vygX3R>nRmu2_W4QkmH@bEvht>LS}YTbJP%{#P&xW^ivkofyO zG2BN!;6vfN>aId4;_k~BTn7QErexjZDnA{rslEZwE?`@J4C1w`{H^dqaEaG$9IpHb zF;t&EiHAEOAMv+02Kl!)`ru=JcB8-IW0XU$0l9|l{|49jx#q~aPvyk}yjZXyJPv-r zT?4e2LVnFxv<$Wr};dlJsJMRpCfobO+W@Qq#2QQ?y zC=vJ)z~dP{qL3{}g10rMsgN&`692yBuWVk&)0@6df%2y})t8l1;2&(R#tar4Ud6uu z+Vl^!Ts)>}1?B6uglHw@{aYHFE2*OH7&93g($XH~J~*d503n=273M7RgH}_5f8q)( zL{?M&{FbJU6W|*+j0AzE2@K4MC=eaqWI<8b{GF?=gPZS$)xo8lhTnPPD&Rf12pMS zp4_&Y9;N*3w%fD$gxZfsUZLbbG9`>>=QEyl7>h6ZO-k?&t#z=O94}eIlVS*?9pY#M*zCl41n{&{Z#BKRFzuG0D;s124?mJDz zw$^PI)f3zecwX2Fd5%JZ=y2XKxAyN8PN-9e=I?vYpu?X*ji2K+_cX!tNKnJ~-_x_HR0otajDQEX-7^&M#5~q@ zr@SADHK}-|x?M6&~_ZiMh|uH}`q89j@bfzOh?`(`UMa z%VhQA0-x=^T{hI;dVxZddwYTU2%{%-gBiZ_syzDdcO{J*;g!*7?Y&!yt^xioKm zF5&vDtvX2j(1f7Tjv~IWjMU@&J3S@ql`UPb%O#V!GJi5xoXK3FUX=;cu}so0PhY=0 zPQ_h29)jLnzbP!PB`67!^;$cp1{a3vCn<)_t< zFeWW=vtT5P4B`{5rAzo(iB7+puhZ`wox~UYf|4)z%aJ&I$*Xp*>-rKSyz7SjEp5%X zH1h?(f|}roW$awP6>!Ta-plkF{fv_Gvf{8^Q8q7ZSKw&0a77vam!09tNB^Sc^1=6|Dc9OnPrOB`h-Klk$R4|g?TDX_f% zNANQLNq;mOfidFp0QbAeFH0F1L-5S?iChE-#;W{pstT|eK%tKe0QTjQ*FEya)||!C z1tsqbq8^bfkM7zhYwr%T6WG4bsSIW(U5K0`1gtJ5(K7#k|AKD)Oep{REQ7xJqPj<8 zQ!Jjr!i%e&n9fm9~a{ui>H&70vPYKlb^k|m001u4)q2fAt6D;LL40!wAK<*8JU-#aO=PK-_zGu~5 z9(`c_YrojL0tCkT?E`Iir}6a%uj8k8Ut;aeqLXFrVadR2xV=Re*T{Ay0EU(M-lO18u@roiIPeKV$7WBWJ4HGX3M-S8Rz{{F2& zjKiHq-y_({YKsKTxEVncNq`Cq1EvfBUv delta 4234 zcmbtXeNa@_6~E{5)U{n?QNRUPv%rEt!Gf>^6rv&<*(!o8NI=Q@ST6A5e&E~p2$)*5 zBbhi8C*sjgoF<*5lg#8p+hjD2&LksAV@Fe)Njfp3lVs8~$&BeFjct=@(n&f!_bs22 z8UN_c+xvOWJ@@?1x#yny#XsTTIam-8hMMv?A6xJxC}ZE=emV$W+2%7gk1+!`F7m(- zj;LA5t`;+DXc58a_fvdmQ6cQdbBmTyd1X;29K_O;nzH@G#o0l{zA<*MqO`&TOkocY zJ^lHE>_Ns9+YviE!dQ}xMs4hvTp3?XS>#ZPn<7zdLnss@DGGZSucQoes#I{{$BqU# zh9#+^R+)oWQtyOE(6zW3&R}HmGt_o2`304~U9t?$oc`mIoj{%9j4Z56&w$6UBYpYE zV^HPq5ww3}IAG{nw2uLEZqkf?vs+9*02ksqa)mnFXc^6~P5rWwkf@kn*Mir@>x^xwsMabC& zFJX61$AXs_n_tDo@p4X9?Q4>?vSO{ff>>W8R)tty?4sgq8Zfk2R9b2rY>ut5sI;yl z5Q~u3xRGJeYx528U8BQNh5OZja=95|PBkRuzKtK`ErW3!S?Tn6;#yx+HB4Pxh2~aWjm8r+fyrUU-nPUY z^_0O?tM#sD8GjFOUEWf3f75?4Ks-5gWO++0E_6iXk5PFb6nVPT=x&<7w#3tV$v3B+) zm0z>3@y5#4>EA+4Twm?=mQ}A=(`}AA#3uWmK+&YHHO$t<^tXng4?g z0Cu0QGPdFLh05n0;In4NHm%6;1Grn)tRasNk<0r@*nB%{w5C7U>(qVQW7aPjMp|7w(o

I zrcVtzt!{jb{K6mY7dqW1^+d+llX4U7Wlzsi{S?g9{gf0tTlrIot)FXJ$DarMPm^0# zuIBnJlLFcE#Kb-9g;~&_n+yFpqN7h%{AFPDkyf5pfV~2Evbl&~0KD2CGy%_k=GI;uSw4P`TKyGfwgk~+XF@X zL%^R0O8Mu2X95SDUjew~aY#V*q1@vqz&-(NY%NdyRGu4;E<)OXMsR*g%e8tqRatFC z4x7J6hA}(XO}cp5=a{r*CI5$<^YgDP5`3sFlYayFOxtZEQxP^TDo^!fmwh)&72tCm z7bvz#ZK&duz0gPK?JQ*r`Aknv=48&A2~SQYnn`QcSlr3@vmMJ(YggC=YAeor?=6rtg$aN*M`D$KLjO$i!#cU!ox1e^)1D}pay!Baz-$sG);bkQ4>>1EK2t9?RJx$u1Fyu~+D zvTA&%GjCxnt;siVwgHtLTUPmInaV%YRQ@@p@{_4b$V?}9%rcXGrkPN*l;FCZnf}Y< zeiL!MjZeq*QVOe+DM~zf`kn=6ED{lVT#$a!O}atcgm)Qofs zeX9RGxq(|IRAyZCjN>o6HjStp>$lPa2sdZ4D;r- zLS(LeBScB7%Zl&ebkW>@cOjVg+}+t!{`u~lWhRFPpTD`x>#c4PA)yT<;wI6Xm=g4b zrT{1i$NJ(yOQ{YH6MBI|j?T0WW5Y8x)e8IO?rC3QPqN|%I6HtZ276!>UAuCqT(>JD zZ`OM7y@J^&?%kDl`ypCGu{Uy!4|8^Smf*3ug2xhq$2h*TYgO`b$!lwroF_P@s@0H; zn^l*STxPxWj~VwGImx4(-a~~qzl9d!S+$Te1s&bR09f1o20V=RP;g`+v@+%Fu~fR> z-3=T2MQAtWGo3<@1w@qckP@g`Z;b{9L})uXC8gYDV6U>qT8Ab^ykIZ2MmCA4h->j` za3?4lV>(3_dN9?3yI^wlknllOvDIt039YZ+XoMi|a`Y$C#-~gW2kmdvTtW6ptj~Tn?o*#CA zqlbdq7(5O*fA?qUPlC-Dia-ImMre0Xx~%(YIK3dejuYdi=w2{RzZ$&__zQp^#g5Ah zZ|}fJ(wE93xPCAVQ}i3vJAGVV79(ws|;keCi4jB^!bQk98rqTuP z!|6x#3Yh;5C{MUsFl=PujkuGZD+`TJsQkhRFCU+AU~f+NFX9(wX6MDkWpvR^X`L3K z*W^I4O2IxJ4~Dh4@f|GW%o)-JO?Vu=dMvWjQrnX@sD@2(%jL^&wY-nBijb+xOhulm z&~D0cYX^S}8b$_d6*@!-d|n-NyU5GePbI6tUM+0U9bg|aC~r;1{| F{{Y, EthereumIntentExecutorT: IntentExecutor, @@ -44,15 +43,24 @@ pub struct IntentEventHandler< RpcClient: SubstrateRpcClient, RpcClientFactory: SubstrateRpcClientFactory, > { - metadata_provider: MetadataProviderT, + metadata_provider: Arc, ethereum_intent_executor: EthereumIntentExecutorT, - key_store: KeyStoreT, rpc_client_factory: RpcClientFactory, - nonce: RwLock, + transaction_signer: Arc< + TransactionSigner< + KeyStoreT, + RpcClient, + RpcClientFactory, + ChainConfig, + MetadataT, + MetadataProviderT, + >, + >, phantom_data: PhantomData<(MetadataT, RpcClient)>, } impl< + ChainConfig: Config, MetadataT, MetadataProviderT: MetadataProvider, EthereumIntentExecutorT: IntentExecutor, @@ -61,6 +69,7 @@ impl< RpcClientFactory: SubstrateRpcClientFactory, > IntentEventHandler< + ChainConfig, MetadataT, MetadataProviderT, EthereumIntentExecutorT, @@ -70,17 +79,25 @@ impl< > { pub fn new( - metadata_provider: MetadataProviderT, + metadata_provider: Arc, ethereum_intent_executor: EthereumIntentExecutorT, - key_store: KeyStoreT, rpc_client_factory: RpcClientFactory, + transaction_signer: Arc< + TransactionSigner< + KeyStoreT, + RpcClient, + RpcClientFactory, + ChainConfig, + MetadataT, + MetadataProviderT, + >, + >, ) -> Self { Self { metadata_provider, ethereum_intent_executor, - key_store, rpc_client_factory, - nonce: RwLock::new(0), + transaction_signer, phantom_data: Default::default(), } } @@ -100,6 +117,7 @@ impl< RpcClientFactory: SubstrateRpcClientFactory + Send + Sync, > EventHandler for IntentEventHandler< + ChainConfig, Metadata, SubxtMetadataProvider, EthereumIntentExecutorT, @@ -119,7 +137,7 @@ impl< log::debug!("Got IntentRequested event: {:?}", event.id); - let metadata = self.metadata_provider.get(event.id.block_num).await; + let metadata = self.metadata_provider.get(Some(event.id.block_num)).await; let pallet = metadata.pallet_by_name(&event.pallet_name).ok_or_else(move || { log::error!( @@ -205,51 +223,13 @@ impl< execution_result, ); - let secret_key_bytes = self - .key_store - .read() - .map_err(|e| { - error!("Could not unseal key: {:?}", e); - }) - .unwrap(); - let signer = subxt_signer::sr25519::Keypair::from_secret_key(secret_key_bytes) - .map_err(|e| { - error!("Could not create secret key: {:?}", e); - }) - .unwrap(); - let mut client = self.rpc_client_factory.new_client().await.map_err(|e| { error!("Could not create RPC client: {:?}", e); RecoverableError })?; - let runtime_version = client.runtime_version().await.map_err(|e| { - error!("Could not get runtime version: {:?}", e); - RecoverableError - })?; - let genesis_hash = client.get_genesis_hash().await.map_err(|e| { - error!("Could not get genesis hash: {:?}", e); - RecoverableError - })?; - let nonce = *self.nonce.read().map_err(|e| { - error!("Could not read nonce: {:?}", e); - RecoverableError - })?; - let params = DefaultExtrinsicParamsBuilder::::new().nonce(nonce).build(); - *self.nonce.write().map_err(|e| { - error!("Could not write nonce: {:?}", e); - RecoverableError - })? = nonce + 1; - let state = tx::ClientState:: { - metadata: { metadata }, - genesis_hash: ChainConfig::Hash::decode(&mut genesis_hash.as_slice()).unwrap(), - runtime_version: tx::RuntimeVersion { - spec_version: runtime_version.spec_version, - transaction_version: runtime_version.transaction_version, - }, - }; - let signed_call = tx::create_signed(&call, &state, &signer, params).unwrap(); - client.submit_tx(signed_call.encoded()).await.map_err(|e| { + let signed_call = self.transaction_signer.sign(call).await; + client.submit_tx(&signed_call).await.map_err(|e| { error!("Error while submitting tx: {:?}", e); RecoverableError })?; diff --git a/tee-worker/omni-executor/parentchain/listener/src/fetcher.rs b/tee-worker/omni-executor/parentchain/listener/src/fetcher.rs index 7d3dfa800f..160dce2347 100644 --- a/tee-worker/omni-executor/parentchain/listener/src/fetcher.rs +++ b/tee-worker/omni-executor/parentchain/listener/src/fetcher.rs @@ -20,20 +20,21 @@ use crate::rpc_client::SubstrateRpcClientFactory; use async_trait::async_trait; use executor_core::fetcher::{EventsFetcher, LastFinalizedBlockNumFetcher}; use log::error; +use std::sync::Arc; /// Used for fetching data from parentchain pub struct Fetcher< RpcClient: SubstrateRpcClient, RpcClientFactory: SubstrateRpcClientFactory, > { - client_factory: RpcClientFactory, + client_factory: Arc, client: Option, } impl> Fetcher { - pub fn new(client_factory: RpcClientFactory) -> Self { + pub fn new(client_factory: Arc) -> Self { Self { client: None, client_factory } } diff --git a/tee-worker/omni-executor/parentchain/listener/src/lib.rs b/tee-worker/omni-executor/parentchain/listener/src/lib.rs index 9f8fab0384..5a0d1ea9d0 100644 --- a/tee-worker/omni-executor/parentchain/listener/src/lib.rs +++ b/tee-worker/omni-executor/parentchain/listener/src/lib.rs @@ -21,22 +21,29 @@ mod listener; mod metadata; mod primitives; mod rpc_client; +mod transaction_signer; use crate::event_handler::IntentEventHandler; use crate::fetcher::Fetcher; use crate::key_store::SubstrateKeyStore; use crate::listener::ParentchainListener; use crate::metadata::SubxtMetadataProvider; +use crate::rpc_client::SubstrateRpcClient; use crate::rpc_client::{SubxtClient, SubxtClientFactory}; +use crate::transaction_signer::TransactionSigner; use executor_core::intent_executor::IntentExecutor; use executor_core::key_store::KeyStore; use executor_core::listener::Listener; use executor_core::sync_checkpoint_repository::FileCheckpointRepository; +use litentry_rococo::runtime_types::core_primitives::teebag; use log::{error, info}; use scale_encode::EncodeAsType; +use std::sync::Arc; use subxt::config::signed_extensions; use subxt::Config; use subxt_core::utils::AccountId32; +use subxt_core::Metadata; +use subxt_signer::sr25519::Keypair; use tokio::runtime::Handle; use tokio::sync::oneshot::Receiver; @@ -92,14 +99,16 @@ pub async fn create_listener, (), > { - let client_factory: SubxtClientFactory = SubxtClientFactory::new(ws_rpc_endpoint); + let client_factory: Arc> = + Arc::new(SubxtClientFactory::new(ws_rpc_endpoint)); - let fetcher = Fetcher::new(client_factory); + let fetcher = Fetcher::new(client_factory.clone()); let last_processed_log_repository = FileCheckpointRepository::new("data/parentchain_last_log.bin"); - let metadata_provider = SubxtMetadataProvider::new(SubxtClientFactory::new(ws_rpc_endpoint)); - let key_store = SubstrateKeyStore::new("/data/parentchain_key.bin".to_string()); + let metadata_provider = + Arc::new(SubxtMetadataProvider::new(SubxtClientFactory::new(ws_rpc_endpoint))); + let key_store = Arc::new(SubstrateKeyStore::new("/data/parentchain_key.bin".to_string())); let secret_key_bytes = key_store .read() .map_err(|e| { @@ -114,11 +123,19 @@ pub async fn create_listener>, + signer: Keypair, + transaction_signer: &Arc< + TransactionSigner< + SubstrateKeyStore, + SubxtClient, + SubxtClientFactory, + CustomConfig, + Metadata, + SubxtMetadataProvider, + >, + >, +) -> Result<(), ()> { + let mut quote = vec![]; + let mut attestation_type = + litentry_rococo::teebag::calls::types::register_enclave::AttestationType::Dcap( + teebag::types::DcapProvider::Intel, + ); + + #[cfg(feature = "gramine-quote")] + { + use std::fs; + use std::fs::File; + use std::io::Write; + let mut f = File::create("/dev/attestation/user_report_data").unwrap(); + let content = signer.public_key().0; + f.write_all(&content).unwrap(); + + quote = fs::read("/dev/attestation/quote").unwrap(); + info!("Attestation quote {:?}", quote); + } + #[cfg(not(feature = "gramine-quote"))] + { + attestation_type = + litentry_rococo::teebag::calls::types::register_enclave::AttestationType::Ignore; + } + + let registration_call = litentry_rococo::tx().teebag().register_enclave( + litentry_rococo::teebag::calls::types::register_enclave::WorkerType::OmniExecutor, + litentry_rococo::teebag::calls::types::register_enclave::WorkerMode::OffChainWorker, + quote, + vec![], + None, + None, + attestation_type, + ); + + let mut client = client_factory.new_client_until_connected().await; + let signed_call = transaction_signer.sign(registration_call).await; + client.submit_tx(&signed_call).await.map_err(|e| { + error!("Error while submitting tx: {:?}", e); + })?; + Ok(()) +} diff --git a/tee-worker/omni-executor/parentchain/listener/src/listener.rs b/tee-worker/omni-executor/parentchain/listener/src/listener.rs index dabd440fa0..f98f87ae52 100644 --- a/tee-worker/omni-executor/parentchain/listener/src/listener.rs +++ b/tee-worker/omni-executor/parentchain/listener/src/listener.rs @@ -38,6 +38,7 @@ pub type ParentchainListener< IntentEventId, BlockEvent, IntentEventHandler< + ChainConfig, Metadata, SubxtMetadataProvider, EthereumIntentExecutor, diff --git a/tee-worker/omni-executor/parentchain/listener/src/metadata.rs b/tee-worker/omni-executor/parentchain/listener/src/metadata.rs index c6e930ab14..0f1b202210 100644 --- a/tee-worker/omni-executor/parentchain/listener/src/metadata.rs +++ b/tee-worker/omni-executor/parentchain/listener/src/metadata.rs @@ -21,7 +21,7 @@ use subxt::{Config, Metadata}; #[async_trait] pub trait MetadataProvider { - async fn get(&self, block_num: u64) -> M; + async fn get(&self, block_num: Option) -> M; } pub struct SubxtMetadataProvider { @@ -36,9 +36,9 @@ impl SubxtMetadataProvider { #[async_trait] impl MetadataProvider for SubxtMetadataProvider { - async fn get(&self, block_num: u64) -> Metadata { + async fn get(&self, block_num: Option) -> Metadata { let mut client = self.client_factory.new_client().await.unwrap(); - let raw_metadata = client.get_raw_metadata(Some(block_num)).await.unwrap(); + let raw_metadata = client.get_raw_metadata(block_num).await.unwrap(); Metadata::decode(&mut raw_metadata.as_slice()).unwrap() } diff --git a/tee-worker/omni-executor/parentchain/listener/src/rpc_client.rs b/tee-worker/omni-executor/parentchain/listener/src/rpc_client.rs index 672aa0a53a..bc43904964 100644 --- a/tee-worker/omni-executor/parentchain/listener/src/rpc_client.rs +++ b/tee-worker/omni-executor/parentchain/listener/src/rpc_client.rs @@ -20,6 +20,8 @@ use log::error; use parity_scale_codec::Encode; use std::marker::PhantomData; use std::ops::Deref; +use std::thread; +use std::time::Duration; use subxt::backend::legacy::LegacyRpcMethods; use subxt::backend::BlockRef; use subxt::config::Header; @@ -157,6 +159,24 @@ impl SubxtClientFactory { pub fn new(url: &str) -> Self { Self { url: url.to_string(), _phantom: PhantomData } } + pub async fn new_client_until_connected(&self) -> SubxtClient { + let mut client: Option> = None; + loop { + if client.is_some() { + break; + } + match self.new_client().await { + Ok(c) => { + client = Some(c); + }, + Err(e) => { + error!("Error creating client: {:?}", e); + }, + }; + thread::sleep(Duration::from_secs(1)) + } + client.unwrap() + } } #[async_trait] diff --git a/tee-worker/omni-executor/parentchain/listener/src/transaction_signer.rs b/tee-worker/omni-executor/parentchain/listener/src/transaction_signer.rs new file mode 100644 index 0000000000..d29bd53cd8 --- /dev/null +++ b/tee-worker/omni-executor/parentchain/listener/src/transaction_signer.rs @@ -0,0 +1,118 @@ +use crate::metadata::{MetadataProvider, SubxtMetadataProvider}; +use crate::rpc_client::{SubstrateRpcClient, SubstrateRpcClientFactory}; +use executor_core::event_handler::Error::RecoverableError; +use executor_core::key_store::KeyStore; +use log::error; +use parity_scale_codec::Decode; +use std::marker::PhantomData; +use std::sync::{Arc, RwLock}; +use subxt_core::config::{DefaultExtrinsicParams, DefaultExtrinsicParamsBuilder}; +use subxt_core::tx::payload::Payload; +use subxt_core::utils::{AccountId32, MultiAddress, MultiSignature}; +use subxt_core::{tx, Config, Metadata}; +use subxt_signer::sr25519::SecretKeyBytes; + +pub struct TransactionSigner< + KeyStoreT, + RpcClient: SubstrateRpcClient, + RpcClientFactory: SubstrateRpcClientFactory, + ChainConfig, + MetadataT, + MetadataProviderT: MetadataProvider, +> { + metadata_provider: Arc, + rpc_client_factory: Arc, + key_store: Arc, + nonce: RwLock, + phantom_data: PhantomData<(RpcClient, ChainConfig, MetadataT)>, +} + +impl< + KeyStoreT: KeyStore, + RpcClient: SubstrateRpcClient, + RpcClientFactory: SubstrateRpcClientFactory, + ChainConfig: Config< + ExtrinsicParams = DefaultExtrinsicParams, + AccountId = AccountId32, + Address = MultiAddress, + Signature = MultiSignature, + >, + > + TransactionSigner< + KeyStoreT, + RpcClient, + RpcClientFactory, + ChainConfig, + Metadata, + SubxtMetadataProvider, + > +{ + pub fn new( + metadata_provider: Arc>, + rpc_client_factory: Arc, + key_store: Arc, + ) -> Self { + Self { + metadata_provider, + rpc_client_factory, + key_store, + //todo: read nonce from chain + nonce: RwLock::new(0), + phantom_data: PhantomData, + } + } + + pub async fn sign(&self, call: Call) -> Vec { + let secret_key_bytes = self + .key_store + .read() + .map_err(|e| { + error!("Could not unseal key: {:?}", e); + }) + .unwrap(); + + let signer = subxt_signer::sr25519::Keypair::from_secret_key(secret_key_bytes) + .map_err(|e| { + error!("Could not create secret key: {:?}", e); + }) + .unwrap(); + let mut client = self.rpc_client_factory.new_client().await.unwrap(); + let runtime_version = client.runtime_version().await.unwrap(); + + let genesis_hash = client.get_genesis_hash().await.unwrap(); + + let nonce = *self + .nonce + .read() + .map_err(|e| { + error!("Could not read nonce: {:?}", e); + RecoverableError + }) + .unwrap(); + + *self + .nonce + .write() + .map_err(|e| { + error!("Could not write nonce: {:?}", e); + RecoverableError + }) + .unwrap() = nonce + 1; + + // we should get latest metadata + let metadata = self.metadata_provider.get(None).await; + + let state = tx::ClientState:: { + metadata: { metadata }, + genesis_hash: ChainConfig::Hash::decode(&mut genesis_hash.as_slice()).unwrap(), + runtime_version: tx::RuntimeVersion { + spec_version: runtime_version.spec_version, + transaction_version: runtime_version.transaction_version, + }, + }; + let params = DefaultExtrinsicParamsBuilder::::new().nonce(nonce).build(); + let signed_call = tx::create_signed(&call, &state, &signer, params).unwrap(); + + signed_call.encoded().to_vec() + } +}