| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658 |
- #![cfg(any(feature = "sbf_c", feature = "sbf_rust"))]
- #![allow(clippy::clone_on_copy)]
- #![allow(clippy::needless_range_loop)]
- #![allow(clippy::needless_borrow)]
- #![allow(clippy::cmp_owned)]
- #![allow(clippy::match_like_matches_macro)]
- #![allow(clippy::unnecessary_cast)]
- #![allow(clippy::uninlined_format_args)]
- #[cfg(feature = "sbf_rust")]
- use {
- agave_feature_set::{self as feature_set, FeatureSet},
- agave_reserved_account_keys::ReservedAccountKeys,
- borsh::{from_slice, to_vec, BorshDeserialize, BorshSerialize},
- solana_account::{AccountSharedData, ReadableAccount, WritableAccount},
- solana_account_info::MAX_PERMITTED_DATA_INCREASE,
- solana_client_traits::SyncClient,
- solana_clock::{UnixTimestamp, MAX_PROCESSING_AGE},
- solana_cluster_type::ClusterType,
- solana_compute_budget::compute_budget::ComputeBudget,
- solana_compute_budget_instruction::instructions_processor::process_compute_budget_instructions,
- solana_compute_budget_interface::ComputeBudgetInstruction,
- solana_fee_calculator::FeeRateGovernor,
- solana_fee_structure::{FeeBin, FeeBudgetLimits, FeeStructure},
- solana_hash::Hash,
- solana_instruction::{error::InstructionError, AccountMeta, Instruction},
- solana_keypair::Keypair,
- solana_loader_v3_interface::instruction as loader_v3_instruction,
- solana_loader_v4_interface::instruction as loader_v4_instruction,
- solana_message::{inner_instruction::InnerInstruction, Message, SanitizedMessage},
- solana_program_runtime::invoke_context::mock_process_instruction,
- solana_pubkey::Pubkey,
- solana_rent::Rent,
- solana_runtime::{
- bank::Bank,
- bank_client::BankClient,
- bank_forks::BankForks,
- genesis_utils::{
- bootstrap_validator_stake_lamports, create_genesis_config,
- create_genesis_config_with_leader_ex, GenesisConfigInfo,
- },
- loader_utils::{
- create_program, instructions_to_load_program_of_loader_v4, load_program_from_file,
- load_program_of_loader_v4, load_upgradeable_buffer,
- },
- },
- solana_runtime_transaction::runtime_transaction::RuntimeTransaction,
- solana_sbf_rust_invoke_dep::*,
- solana_sbf_rust_realloc_dep::*,
- solana_sbf_rust_realloc_invoke_dep::*,
- solana_sbpf::vm::ContextObject,
- solana_sdk_ids::sysvar::{self as sysvar, clock},
- solana_sdk_ids::{bpf_loader, bpf_loader_deprecated, bpf_loader_upgradeable, loader_v4},
- solana_signer::Signer,
- solana_svm::{
- transaction_commit_result::{CommittedTransaction, TransactionCommitResult},
- transaction_processor::ExecutionRecordingConfig,
- },
- solana_svm_timings::ExecuteTimings,
- solana_svm_transaction::svm_message::SVMStaticMessage,
- solana_svm_type_overrides::rand,
- solana_system_interface::{program as system_program, MAX_PERMITTED_DATA_LENGTH},
- solana_transaction::Transaction,
- solana_transaction_error::TransactionError,
- std::{
- assert_eq,
- cell::RefCell,
- str::FromStr,
- sync::{Arc, RwLock},
- time::Duration,
- },
- test_case::test_matrix,
- };
- #[cfg(all(
- any(feature = "sbf_c", feature = "sbf_rust"),
- not(feature = "sbf_sanity_list")
- ))]
- use {
- solana_account::Account,
- solana_program_runtime::sysvar_cache::SysvarCache,
- solana_sdk_ids::sysvar::rent,
- solana_svm_test_harness::{self as harness, fixture::instr_context::InstrContext},
- };
- #[cfg(feature = "sbf_rust")]
- fn process_transaction_and_record_inner(
- bank: &Bank,
- tx: Transaction,
- ) -> (
- Result<(), TransactionError>,
- Vec<Vec<InnerInstruction>>,
- Vec<String>,
- u64,
- ) {
- let commit_result = load_execute_and_commit_transaction(bank, tx);
- let CommittedTransaction {
- inner_instructions,
- log_messages,
- status,
- executed_units,
- ..
- } = commit_result.unwrap();
- let inner_instructions = inner_instructions.expect("cpi recording should be enabled");
- let log_messages = log_messages.expect("log recording should be enabled");
- (status, inner_instructions, log_messages, executed_units)
- }
- #[cfg(feature = "sbf_rust")]
- fn load_execute_and_commit_transaction(bank: &Bank, tx: Transaction) -> TransactionCommitResult {
- let txs = vec![tx];
- let tx_batch = bank.prepare_batch_for_tests(txs);
- let mut commit_results = bank
- .load_execute_and_commit_transactions(
- &tx_batch,
- MAX_PROCESSING_AGE,
- ExecutionRecordingConfig {
- enable_cpi_recording: true,
- enable_log_recording: true,
- enable_return_data_recording: false,
- enable_transaction_balance_recording: false,
- },
- &mut ExecuteTimings::default(),
- None,
- )
- .0;
- commit_results.pop().unwrap()
- }
- #[cfg(feature = "sbf_rust")]
- fn bank_with_feature_activated(
- bank_forks: &RwLock<BankForks>,
- parent: Arc<Bank>,
- feature_id: &Pubkey,
- ) -> Arc<Bank> {
- let slot = parent.slot().saturating_add(1);
- let mut bank = Bank::new_from_parent(parent, &Pubkey::new_unique(), slot);
- bank.activate_feature(feature_id);
- bank_forks
- .write()
- .unwrap()
- .insert(bank)
- .clone_without_scheduler()
- }
- #[cfg(feature = "sbf_rust")]
- fn bank_with_feature_deactivated(
- bank_forks: &RwLock<BankForks>,
- parent: Arc<Bank>,
- feature_id: &Pubkey,
- ) -> Arc<Bank> {
- let slot = parent.slot().saturating_add(1);
- let mut bank = Bank::new_from_parent(parent, &Pubkey::new_unique(), slot);
- bank.deactivate_feature(feature_id);
- bank_forks
- .write()
- .unwrap()
- .insert(bank)
- .clone_without_scheduler()
- }
- #[cfg(feature = "sbf_rust")]
- const LOADED_ACCOUNTS_DATA_SIZE_LIMIT_FOR_TEST: u32 = 64 * 1024 * 1024;
- #[test]
- #[cfg(any(feature = "sbf_c", feature = "sbf_rust"))]
- fn test_program_sbf_sanity() {
- agave_logger::setup();
- let mut programs = Vec::new();
- #[cfg(feature = "sbf_c")]
- {
- programs.extend_from_slice(&[
- ("alloc", true),
- ("alt_bn128", true),
- ("alt_bn128_compression", true),
- ("sbf_to_sbf", true),
- ("float", true),
- ("multiple_static", true),
- ("noop", true),
- ("noop++", true),
- ("panic", false),
- ("poseidon", true),
- ("relative_call", true),
- ("return_data", true),
- ("sanity", true),
- ("sanity++", true),
- ("secp256k1_recover", true),
- ("sha", true),
- ("stdlib", true),
- ("struct_pass", true),
- ("struct_ret", true),
- ]);
- }
- #[cfg(feature = "sbf_rust")]
- {
- programs.extend_from_slice(&[
- ("solana_sbf_rust_128bit", true),
- ("solana_sbf_rust_alloc", true),
- ("solana_sbf_rust_alt_bn128", true),
- ("solana_sbf_rust_alt_bn128_compression", true),
- ("solana_sbf_rust_curve25519", true),
- ("solana_sbf_rust_custom_heap", true),
- ("solana_sbf_rust_dep_crate", true),
- ("solana_sbf_rust_external_spend", false),
- ("solana_sbf_rust_iter", true),
- ("solana_sbf_rust_many_args", true),
- ("solana_sbf_rust_mem", true),
- ("solana_sbf_rust_membuiltins", true),
- ("solana_sbf_rust_noop", true),
- ("solana_sbf_rust_panic", false),
- ("solana_sbf_rust_param_passing", true),
- ("solana_sbf_rust_poseidon", true),
- ("solana_sbf_rust_rand", true),
- ("solana_sbf_rust_remaining_compute_units", true),
- ("solana_sbf_rust_sanity", true),
- ("solana_sbf_rust_secp256k1_recover", true),
- ("solana_sbf_rust_sha", true),
- ]);
- }
- #[cfg(all(feature = "sbf_rust", feature = "sbf_sanity_list"))]
- {
- // This code generates the list of sanity programs for a CI job to build with
- // cargo-build-sbf and ensure it is working correctly.
- use std::{env, fs::File, io::Write};
- let current_dir = env::current_dir().unwrap();
- let mut file =
- File::create(current_dir.join("target").join("sanity_programs.txt")).unwrap();
- for program in programs.iter() {
- writeln!(file, "{}", program.0.trim_start_matches("solana_sbf_rust_"))
- .expect("Failed to write to file");
- }
- }
- #[cfg(not(feature = "sbf_sanity_list"))]
- for program in programs.iter() {
- println!("Test program: {:?}", program.0);
- let program_elf = harness::file::load_program_elf(program.0);
- let program_id = Pubkey::new_unique();
- let feature_set = FeatureSet::all_enabled();
- let pubkey1 = Pubkey::new_unique();
- let pubkey2 = Pubkey::new_unique();
- let account_metas = vec![
- AccountMeta::new(pubkey1, true),
- AccountMeta::new(pubkey2, false),
- ];
- let instruction = Instruction::new_with_bytes(program_id, &[1], account_metas);
- let accounts = vec![
- (
- program_id,
- Account {
- owner: loader_v4::id(),
- ..Default::default() // <-- Stubbed
- },
- ),
- (pubkey1, Account::default()),
- (pubkey2, Account::default()),
- ];
- let compute_budget = ComputeBudget::new_with_defaults(false, false);
- let mut program_cache =
- harness::program_cache::new_with_builtins(&feature_set, /* slot */ 0);
- harness::program_cache::add_program(
- &mut program_cache,
- &program_id,
- &loader_v4::id(),
- &program_elf,
- &feature_set,
- &compute_budget,
- );
- let mut sysvar_cache = SysvarCache::default();
- sysvar_cache.fill_missing_entries(|pubkey, callbackback| {
- if pubkey == &rent::id() {
- // Add the default Rent sysvar.
- let rent = Rent::default();
- let rent_data = bincode::serialize(&rent).unwrap();
- callbackback(&rent_data);
- }
- });
- let context = InstrContext {
- feature_set,
- accounts,
- instruction: instruction.into(),
- cu_avail: compute_budget.compute_unit_limit,
- };
- let effects = harness::instr::execute_instr(
- context,
- &compute_budget,
- &mut program_cache,
- &sysvar_cache,
- )
- .unwrap();
- let result = match effects.result {
- Some(err) => Err(err),
- None => Ok(()),
- };
- if program.1 {
- assert!(result.is_ok(), "{result:?}");
- } else {
- assert!(result.is_err(), "{result:?}");
- }
- }
- }
- #[test]
- #[cfg(any(feature = "sbf_c", feature = "sbf_rust"))]
- fn test_program_sbf_loader_deprecated() {
- agave_logger::setup();
- let mut programs = Vec::new();
- #[cfg(feature = "sbf_c")]
- {
- programs.extend_from_slice(&[("deprecated_loader")]);
- }
- #[cfg(feature = "sbf_rust")]
- {
- programs.extend_from_slice(&[("solana_sbf_rust_deprecated_loader")]);
- }
- for program in programs.iter() {
- println!("Test program: {:?}", program);
- let GenesisConfigInfo {
- mut genesis_config,
- mint_keypair,
- ..
- } = create_genesis_config(50);
- genesis_config
- .accounts
- .remove(&agave_feature_set::disable_deploy_of_alloc_free_syscall::id())
- .unwrap();
- let (bank, bank_forks) = Bank::new_with_bank_forks_for_tests(&genesis_config);
- let program_id = create_program(&bank, &bpf_loader_deprecated::id(), program);
- let mut bank_client = BankClient::new_shared(bank);
- bank_client
- .advance_slot(1, bank_forks.as_ref(), &Pubkey::default())
- .expect("Failed to advance the slot");
- let account_metas = vec![AccountMeta::new(mint_keypair.pubkey(), true)];
- let instruction = Instruction::new_with_bytes(program_id, &[255], account_metas);
- let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
- assert!(result.is_ok());
- }
- }
- #[test]
- #[cfg(feature = "sbf_rust")]
- #[should_panic(expected = "called `Result::unwrap()` on an `Err` value: \
- TransactionError(InstructionError(0, InvalidAccountData))")]
- fn test_sol_alloc_free_no_longer_deployable_with_upgradeable_loader() {
- agave_logger::setup();
- let GenesisConfigInfo {
- genesis_config,
- mint_keypair,
- ..
- } = create_genesis_config(50);
- let (bank, bank_forks) = Bank::new_with_bank_forks_for_tests(&genesis_config);
- let mut bank_client = BankClient::new_shared(bank.clone());
- let authority_keypair = Keypair::new();
- // Populate loader account with `solana_sbf_rust_deprecated_loader` elf, which
- // depends on `sol_alloc_free_` syscall. This can be verified with
- // $ elfdump solana_sbf_rust_deprecated_loader.so
- // : 0000000000001ab8 000000070000000a R_BPF_64_32 0000000000000000 sol_alloc_free_
- // In the symbol table, there is `sol_alloc_free_`.
- // In fact, `sol_alloc_free_` is called from sbf allocator, which is originated from
- // AccountInfo::realloc() in the program code.
- // Expect that deployment to fail. B/C during deployment, there is an elf
- // verification step, which uses the runtime to look up relocatable symbols
- // in elf inside syscall table. In this case, `sol_alloc_free_` can't be
- // found in syscall table. Hence, the verification fails and the deployment
- // fails.
- let (_bank, _program_id) = load_program_of_loader_v4(
- &mut bank_client,
- &bank_forks,
- &mint_keypair,
- &authority_keypair,
- "solana_sbf_rust_deprecated_loader",
- );
- }
- #[test]
- #[cfg(feature = "sbf_rust")]
- fn test_program_sbf_duplicate_accounts() {
- agave_logger::setup();
- let mut programs = Vec::new();
- #[cfg(feature = "sbf_c")]
- {
- programs.extend_from_slice(&[("dup_accounts")]);
- }
- #[cfg(feature = "sbf_rust")]
- {
- programs.extend_from_slice(&[("solana_sbf_rust_dup_accounts")]);
- }
- for program in programs.iter() {
- println!("Test program: {:?}", program);
- let GenesisConfigInfo {
- genesis_config,
- mint_keypair,
- ..
- } = create_genesis_config(50);
- let (bank, bank_forks) = Bank::new_with_bank_forks_for_tests(&genesis_config);
- let mut bank_client = BankClient::new_shared(bank.clone());
- let authority_keypair = Keypair::new();
- let (bank, program_id) = load_program_of_loader_v4(
- &mut bank_client,
- &bank_forks,
- &mint_keypair,
- &authority_keypair,
- program,
- );
- let payee_account = AccountSharedData::new(10, 1, &program_id);
- let payee_pubkey = Pubkey::new_unique();
- bank.store_account(&payee_pubkey, &payee_account);
- let account = AccountSharedData::new(10, 1, &program_id);
- let pubkey = Pubkey::new_unique();
- let account_metas = vec![
- AccountMeta::new(mint_keypair.pubkey(), true),
- AccountMeta::new(payee_pubkey, false),
- AccountMeta::new(pubkey, false),
- AccountMeta::new(pubkey, false),
- ];
- bank.store_account(&pubkey, &account);
- let instruction = Instruction::new_with_bytes(program_id, &[1], account_metas.clone());
- let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
- let data = bank_client.get_account_data(&pubkey).unwrap().unwrap();
- assert!(result.is_ok());
- assert_eq!(data[0], 1);
- bank.store_account(&pubkey, &account);
- let instruction = Instruction::new_with_bytes(program_id, &[2], account_metas.clone());
- let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
- let data = bank_client.get_account_data(&pubkey).unwrap().unwrap();
- assert!(result.is_ok());
- assert_eq!(data[0], 2);
- bank.store_account(&pubkey, &account);
- let instruction = Instruction::new_with_bytes(program_id, &[3], account_metas.clone());
- let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
- let data = bank_client.get_account_data(&pubkey).unwrap().unwrap();
- assert!(result.is_ok());
- assert_eq!(data[0], 3);
- bank.store_account(&pubkey, &account);
- let instruction = Instruction::new_with_bytes(program_id, &[4], account_metas.clone());
- let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
- let lamports = bank_client.get_balance(&pubkey).unwrap();
- assert!(result.is_ok());
- assert_eq!(lamports, 11);
- bank.store_account(&pubkey, &account);
- let instruction = Instruction::new_with_bytes(program_id, &[5], account_metas.clone());
- let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
- let lamports = bank_client.get_balance(&pubkey).unwrap();
- assert!(result.is_ok());
- assert_eq!(lamports, 12);
- bank.store_account(&pubkey, &account);
- let instruction = Instruction::new_with_bytes(program_id, &[6], account_metas.clone());
- let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
- let lamports = bank_client.get_balance(&pubkey).unwrap();
- assert!(result.is_ok());
- assert_eq!(lamports, 13);
- let keypair = Keypair::new();
- let pubkey = keypair.pubkey();
- let account_metas = vec![
- AccountMeta::new(mint_keypair.pubkey(), true),
- AccountMeta::new(payee_pubkey, false),
- AccountMeta::new(pubkey, false),
- AccountMeta::new_readonly(pubkey, true),
- AccountMeta::new_readonly(program_id, false),
- ];
- bank.store_account(&pubkey, &account);
- let instruction = Instruction::new_with_bytes(program_id, &[7], account_metas.clone());
- let message = Message::new(&[instruction], Some(&mint_keypair.pubkey()));
- let result = bank_client.send_and_confirm_message(&[&mint_keypair, &keypair], message);
- assert!(result.is_ok());
- }
- }
- #[test]
- #[cfg(feature = "sbf_rust")]
- fn test_program_sbf_error_handling() {
- agave_logger::setup();
- let mut programs = Vec::new();
- #[cfg(feature = "sbf_c")]
- {
- programs.extend_from_slice(&[("error_handling")]);
- }
- #[cfg(feature = "sbf_rust")]
- {
- programs.extend_from_slice(&[("solana_sbf_rust_error_handling")]);
- }
- for program in programs.iter() {
- println!("Test program: {:?}", program);
- let GenesisConfigInfo {
- genesis_config,
- mint_keypair,
- ..
- } = create_genesis_config(50);
- let (bank, bank_forks) = Bank::new_with_bank_forks_for_tests(&genesis_config);
- let mut bank_client = BankClient::new_shared(bank);
- let authority_keypair = Keypair::new();
- let (_bank, program_id) = load_program_of_loader_v4(
- &mut bank_client,
- &bank_forks,
- &mint_keypair,
- &authority_keypair,
- program,
- );
- let account_metas = vec![AccountMeta::new(mint_keypair.pubkey(), true)];
- let instruction = Instruction::new_with_bytes(program_id, &[1], account_metas.clone());
- let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
- assert!(result.is_ok());
- let instruction = Instruction::new_with_bytes(program_id, &[2], account_metas.clone());
- let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
- assert_eq!(
- result.unwrap_err().unwrap(),
- TransactionError::InstructionError(0, InstructionError::InvalidAccountData)
- );
- let instruction = Instruction::new_with_bytes(program_id, &[3], account_metas.clone());
- let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
- assert_eq!(
- result.unwrap_err().unwrap(),
- TransactionError::InstructionError(0, InstructionError::Custom(0))
- );
- let instruction = Instruction::new_with_bytes(program_id, &[4], account_metas.clone());
- let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
- assert_eq!(
- result.unwrap_err().unwrap(),
- TransactionError::InstructionError(0, InstructionError::Custom(42))
- );
- let instruction = Instruction::new_with_bytes(program_id, &[5], account_metas.clone());
- let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
- let result = result.unwrap_err().unwrap();
- if TransactionError::InstructionError(0, InstructionError::InvalidInstructionData) != result
- {
- assert_eq!(
- result,
- TransactionError::InstructionError(0, InstructionError::InvalidError)
- );
- }
- let instruction = Instruction::new_with_bytes(program_id, &[6], account_metas.clone());
- let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
- let result = result.unwrap_err().unwrap();
- if TransactionError::InstructionError(0, InstructionError::InvalidInstructionData) != result
- {
- assert_eq!(
- result,
- TransactionError::InstructionError(0, InstructionError::InvalidError)
- );
- }
- let instruction = Instruction::new_with_bytes(program_id, &[7], account_metas.clone());
- let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
- let result = result.unwrap_err().unwrap();
- if TransactionError::InstructionError(0, InstructionError::InvalidInstructionData) != result
- {
- assert_eq!(
- result,
- TransactionError::InstructionError(0, InstructionError::AccountBorrowFailed)
- );
- }
- let instruction = Instruction::new_with_bytes(program_id, &[8], account_metas.clone());
- let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
- assert_eq!(
- result.unwrap_err().unwrap(),
- TransactionError::InstructionError(0, InstructionError::InvalidInstructionData)
- );
- let instruction = Instruction::new_with_bytes(program_id, &[9], account_metas.clone());
- let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
- assert_eq!(
- result.unwrap_err().unwrap(),
- TransactionError::InstructionError(0, InstructionError::MaxSeedLengthExceeded)
- );
- }
- }
- #[test]
- #[cfg(any(feature = "sbf_c", feature = "sbf_rust"))]
- fn test_return_data_and_log_data_syscall() {
- agave_logger::setup();
- let mut programs = Vec::new();
- #[cfg(feature = "sbf_c")]
- {
- programs.extend_from_slice(&[("log_data")]);
- }
- #[cfg(feature = "sbf_rust")]
- {
- programs.extend_from_slice(&[("solana_sbf_rust_log_data")]);
- }
- for program in programs.iter() {
- let GenesisConfigInfo {
- genesis_config,
- mint_keypair,
- ..
- } = create_genesis_config(50);
- let (bank, bank_forks) = Bank::new_with_bank_forks_for_tests(&genesis_config);
- let mut bank_client = BankClient::new_shared(bank.clone());
- let authority_keypair = Keypair::new();
- let (bank, program_id) = load_program_of_loader_v4(
- &mut bank_client,
- &bank_forks,
- &mint_keypair,
- &authority_keypair,
- program,
- );
- bank.freeze();
- let account_metas = vec![AccountMeta::new(mint_keypair.pubkey(), true)];
- let instruction =
- Instruction::new_with_bytes(program_id, &[1, 2, 3, 0, 4, 5, 6], account_metas);
- let blockhash = bank.last_blockhash();
- let message = Message::new(&[instruction], Some(&mint_keypair.pubkey()));
- let transaction = Transaction::new(&[&mint_keypair], message, blockhash);
- let sanitized_tx = RuntimeTransaction::from_transaction_for_tests(transaction);
- let result = bank.simulate_transaction(&sanitized_tx, false);
- assert!(result.result.is_ok());
- assert_eq!(result.logs[1], "Program data: AQID BAUG");
- assert_eq!(
- result.logs[3],
- format!("Program return: {} CAFE", program_id)
- );
- }
- }
- #[test]
- #[cfg(feature = "sbf_rust")]
- fn test_program_sbf_invoke_sanity() {
- agave_logger::setup();
- #[derive(Debug)]
- #[allow(dead_code)]
- enum Languages {
- C,
- Rust,
- }
- let mut programs = Vec::new();
- #[cfg(feature = "sbf_c")]
- {
- programs.push((Languages::C, "invoke", "invoked", "noop"));
- }
- #[cfg(feature = "sbf_rust")]
- {
- programs.push((
- Languages::Rust,
- "solana_sbf_rust_invoke",
- "solana_sbf_rust_invoked",
- "solana_sbf_rust_noop",
- ));
- }
- for program in programs.iter() {
- println!("Test program: {:?}", program);
- let GenesisConfigInfo {
- genesis_config,
- mint_keypair,
- ..
- } = create_genesis_config(50);
- let (bank, bank_forks) = Bank::new_with_bank_forks_for_tests(&genesis_config);
- let mut bank_client = BankClient::new_shared(bank.clone());
- let authority_keypair = Keypair::new();
- let (_bank, invoke_program_id) = load_program_of_loader_v4(
- &mut bank_client,
- &bank_forks,
- &mint_keypair,
- &authority_keypair,
- program.1,
- );
- let (_bank, invoked_program_id) = load_program_of_loader_v4(
- &mut bank_client,
- &bank_forks,
- &mint_keypair,
- &authority_keypair,
- program.2,
- );
- let (bank, noop_program_id) = load_program_of_loader_v4(
- &mut bank_client,
- &bank_forks,
- &mint_keypair,
- &authority_keypair,
- program.3,
- );
- let argument_keypair = Keypair::new();
- let account = AccountSharedData::new(42, 100, &invoke_program_id);
- bank.store_account(&argument_keypair.pubkey(), &account);
- let invoked_argument_keypair = Keypair::new();
- let account = AccountSharedData::new(20, 10, &invoked_program_id);
- bank.store_account(&invoked_argument_keypair.pubkey(), &account);
- let from_keypair = Keypair::new();
- let account = AccountSharedData::new(84, 0, &system_program::id());
- bank.store_account(&from_keypair.pubkey(), &account);
- let unexecutable_program_keypair = Keypair::new();
- let account = AccountSharedData::new(1, 0, &bpf_loader::id());
- bank.store_account(&unexecutable_program_keypair.pubkey(), &account);
- let noop_program_keypair = Keypair::new();
- let account = AccountSharedData::new(42, 5, &noop_program_id);
- bank.store_account(&noop_program_keypair.pubkey(), &account);
- let (derived_key1, bump_seed1) =
- Pubkey::find_program_address(&[b"You pass butter"], &invoke_program_id);
- let (derived_key2, bump_seed2) =
- Pubkey::find_program_address(&[b"Lil'", b"Bits"], &invoked_program_id);
- let (derived_key3, bump_seed3) =
- Pubkey::find_program_address(&[derived_key2.as_ref()], &invoked_program_id);
- let mint_pubkey = mint_keypair.pubkey();
- let account_metas = vec![
- AccountMeta::new(mint_pubkey, true),
- AccountMeta::new(argument_keypair.pubkey(), true),
- AccountMeta::new_readonly(invoked_program_id, false),
- AccountMeta::new(invoked_argument_keypair.pubkey(), true),
- AccountMeta::new_readonly(invoked_program_id, false),
- AccountMeta::new(argument_keypair.pubkey(), true),
- AccountMeta::new(derived_key1, false),
- AccountMeta::new(derived_key2, false),
- AccountMeta::new_readonly(derived_key3, false),
- AccountMeta::new_readonly(system_program::id(), false),
- AccountMeta::new(from_keypair.pubkey(), true),
- AccountMeta::new_readonly(solana_sdk_ids::ed25519_program::id(), false),
- AccountMeta::new_readonly(invoke_program_id, false),
- AccountMeta::new_readonly(unexecutable_program_keypair.pubkey(), false),
- AccountMeta::new_readonly(noop_program_id, false),
- ];
- let do_invoke = |test: u8, additional_instructions: &[Instruction], bank: &Bank| {
- let instruction_data = &[test, bump_seed1, bump_seed2, bump_seed3];
- let signers = vec![
- &mint_keypair,
- &argument_keypair,
- &invoked_argument_keypair,
- &from_keypair,
- ];
- let mut instructions = vec![Instruction::new_with_bytes(
- invoke_program_id,
- instruction_data,
- account_metas.clone(),
- )];
- instructions.extend_from_slice(additional_instructions);
- let message = Message::new(&instructions, Some(&mint_pubkey));
- let tx = Transaction::new(&signers, message.clone(), bank.last_blockhash());
- let (result, inner_instructions, log_messages, executed_units) =
- process_transaction_and_record_inner(bank, tx);
- let invoked_programs: Vec<Pubkey> = inner_instructions
- .first()
- .map(|instructions| {
- instructions
- .iter()
- .filter_map(|ix| {
- message
- .account_keys
- .get(ix.instruction.program_id_index as usize)
- })
- .cloned()
- .collect()
- })
- .unwrap_or_default();
- let no_invoked_programs: Vec<Pubkey> = inner_instructions
- .get(1)
- .map(|instructions| {
- instructions
- .iter()
- .filter_map(|ix| {
- message
- .account_keys
- .get(ix.instruction.program_id_index as usize)
- })
- .cloned()
- .collect()
- })
- .unwrap_or_default();
- (
- result,
- log_messages,
- executed_units,
- invoked_programs,
- no_invoked_programs,
- )
- };
- // success cases
- let do_invoke_success = |test: u8,
- additional_instructions: &[Instruction],
- expected_invoked_programs: &[Pubkey],
- bank: &Bank| {
- println!("Running success test #{:?}", test);
- let (result, _log_messages, _executed_units, invoked_programs, no_invoked_programs) =
- do_invoke(test, additional_instructions, bank);
- assert_eq!(result, Ok(()));
- assert_eq!(invoked_programs.len(), expected_invoked_programs.len());
- assert_eq!(invoked_programs, expected_invoked_programs);
- assert_eq!(no_invoked_programs.len(), 0);
- };
- do_invoke_success(
- TEST_SUCCESS,
- &[Instruction::new_with_bytes(noop_program_id, &[], vec![])],
- match program.0 {
- Languages::C => vec![
- system_program::id(),
- system_program::id(),
- invoked_program_id.clone(),
- invoked_program_id.clone(),
- invoked_program_id.clone(),
- invoked_program_id.clone(),
- invoked_program_id.clone(),
- invoked_program_id.clone(),
- invoked_program_id.clone(),
- invoked_program_id.clone(),
- invoked_program_id.clone(),
- invoked_program_id.clone(),
- invoked_program_id.clone(),
- invoked_program_id.clone(),
- invoked_program_id.clone(),
- invoked_program_id.clone(),
- invoked_program_id.clone(),
- invoked_program_id.clone(),
- invoked_program_id.clone(),
- ],
- Languages::Rust => vec![
- system_program::id(),
- system_program::id(),
- invoked_program_id.clone(),
- invoked_program_id.clone(),
- invoked_program_id.clone(),
- invoked_program_id.clone(),
- invoked_program_id.clone(),
- invoked_program_id.clone(),
- invoked_program_id.clone(),
- invoked_program_id.clone(),
- invoked_program_id.clone(),
- invoked_program_id.clone(),
- invoked_program_id.clone(),
- invoked_program_id.clone(),
- invoked_program_id.clone(),
- invoked_program_id.clone(),
- invoked_program_id.clone(),
- invoked_program_id.clone(),
- invoked_program_id.clone(),
- invoked_program_id.clone(),
- invoked_program_id.clone(),
- system_program::id(),
- invoked_program_id.clone(),
- invoked_program_id.clone(),
- ],
- }
- .as_ref(),
- &bank,
- );
- // With SIMD-0268 enabled, eight nested invokes should pass.
- let bank = bank_with_feature_activated(
- &bank_forks,
- bank,
- &feature_set::raise_cpi_nesting_limit_to_8::id(),
- );
- assert!(bank
- .feature_set
- .is_active(&feature_set::raise_cpi_nesting_limit_to_8::id()));
- {
- // Reset the account balances for `ARGUMENT` and `INVOKED_ARGUMENT`
- let account = AccountSharedData::new(42, 100, &invoke_program_id);
- bank.store_account(&argument_keypair.pubkey(), &account);
- let account = AccountSharedData::new(20, 10, &invoked_program_id);
- bank.store_account(&invoked_argument_keypair.pubkey(), &account);
- }
- do_invoke_success(
- TEST_NESTED_INVOKE_SIMD_0268_OK,
- &[],
- &[invoked_program_id.clone(); 16], // 16, 8 for each invoke
- &bank,
- );
- do_invoke_success(
- TEST_MAX_ACCOUNT_INFOS_OK,
- &[],
- std::slice::from_ref(&invoked_program_id),
- &bank,
- );
- do_invoke_success(
- TEST_CU_USAGE_MINIMUM,
- &[],
- std::slice::from_ref(&noop_program_id),
- &bank,
- );
- do_invoke_success(
- TEST_CU_USAGE_BASELINE,
- &[],
- std::slice::from_ref(&noop_program_id),
- &bank,
- );
- do_invoke_success(
- TEST_CU_USAGE_MAX,
- &[],
- std::slice::from_ref(&noop_program_id),
- &bank,
- );
- let bank = bank_with_feature_deactivated(
- &bank_forks,
- bank,
- &feature_set::increase_cpi_account_info_limit::id(),
- );
- assert!(!bank
- .feature_set
- .is_active(&feature_set::increase_cpi_account_info_limit::id()));
- do_invoke_success(
- TEST_MAX_ACCOUNT_INFOS_OK_BEFORE_SIMD_0339,
- &[],
- std::slice::from_ref(&invoked_program_id),
- &bank,
- );
- let bank = bank_with_feature_deactivated(
- &bank_forks,
- bank,
- &feature_set::increase_tx_account_lock_limit::id(),
- );
- assert!(!bank
- .feature_set
- .is_active(&feature_set::increase_tx_account_lock_limit::id()));
- do_invoke_success(
- TEST_MAX_ACCOUNT_INFOS_OK_BEFORE_INCREASE_TX_ACCOUNT_LOCK_BEFORE_SIMD_0339,
- &[],
- std::slice::from_ref(&invoked_program_id),
- &bank,
- );
- let bank = bank_with_feature_activated(
- &bank_forks,
- bank,
- &feature_set::increase_tx_account_lock_limit::id(),
- );
- assert!(bank
- .feature_set
- .is_active(&feature_set::increase_tx_account_lock_limit::id()));
- let bank = bank_with_feature_activated(
- &bank_forks,
- bank,
- &feature_set::increase_cpi_account_info_limit::id(),
- );
- assert!(bank
- .feature_set
- .is_active(&feature_set::increase_cpi_account_info_limit::id()));
- // failure cases
- let do_invoke_failure_test_local_with_compute_check =
- |test: u8,
- expected_error: TransactionError,
- expected_invoked_programs: &[Pubkey],
- expected_log_messages: Option<Vec<String>>,
- should_deplete_compute_meter: bool,
- bank: &Bank| {
- println!("Running failure test #{:?}", test);
- let compute_unit_limit = 1_000_000;
- let (result, log_messages, executed_units, invoked_programs, _) = do_invoke(
- test,
- &[ComputeBudgetInstruction::set_compute_unit_limit(
- compute_unit_limit,
- )],
- bank,
- );
- assert_eq!(result, Err(expected_error));
- assert_eq!(invoked_programs, expected_invoked_programs);
- if should_deplete_compute_meter {
- assert_eq!(executed_units, compute_unit_limit as u64);
- } else {
- assert!(executed_units < compute_unit_limit as u64);
- }
- if let Some(expected_log_messages) = expected_log_messages {
- assert_eq!(log_messages.len(), expected_log_messages.len());
- expected_log_messages
- .into_iter()
- .zip(log_messages)
- .for_each(|(expected_log_message, log_message)| {
- if expected_log_message != String::from("skip") {
- assert_eq!(log_message, expected_log_message);
- }
- });
- }
- };
- let do_invoke_failure_test_local =
- |test: u8,
- expected_error: TransactionError,
- expected_invoked_programs: &[Pubkey],
- expected_log_messages: Option<Vec<String>>,
- bank: &Bank| {
- do_invoke_failure_test_local_with_compute_check(
- test,
- expected_error,
- expected_invoked_programs,
- expected_log_messages,
- false, // should_deplete_compute_meter
- bank,
- )
- };
- let program_lang = match program.0 {
- Languages::Rust => "Rust",
- Languages::C => "C",
- };
- do_invoke_failure_test_local(
- TEST_PRIVILEGE_ESCALATION_SIGNER,
- TransactionError::InstructionError(0, InstructionError::PrivilegeEscalation),
- std::slice::from_ref(&invoked_program_id),
- None,
- &bank,
- );
- do_invoke_failure_test_local(
- TEST_PRIVILEGE_ESCALATION_WRITABLE,
- TransactionError::InstructionError(0, InstructionError::PrivilegeEscalation),
- std::slice::from_ref(&invoked_program_id),
- None,
- &bank,
- );
- do_invoke_failure_test_local(
- TEST_PPROGRAM_NOT_OWNED_BY_LOADER,
- TransactionError::InstructionError(0, InstructionError::UnsupportedProgramId),
- &[argument_keypair.pubkey()],
- None,
- &bank,
- );
- do_invoke_failure_test_local(
- TEST_PPROGRAM_NOT_EXECUTABLE,
- TransactionError::InstructionError(0, InstructionError::UnsupportedProgramId),
- &[unexecutable_program_keypair.pubkey()],
- None,
- &bank,
- );
- do_invoke_failure_test_local(
- TEST_EMPTY_ACCOUNTS_SLICE,
- TransactionError::InstructionError(0, InstructionError::MissingAccount),
- &[],
- None,
- &bank,
- );
- do_invoke_failure_test_local(
- TEST_CAP_SEEDS,
- TransactionError::InstructionError(0, InstructionError::MaxSeedLengthExceeded),
- &[],
- None,
- &bank,
- );
- do_invoke_failure_test_local(
- TEST_CAP_SIGNERS,
- TransactionError::InstructionError(0, InstructionError::ProgramFailedToComplete),
- &[],
- None,
- &bank,
- );
- do_invoke_failure_test_local(
- TEST_MAX_INSTRUCTION_DATA_LEN_EXCEEDED,
- TransactionError::InstructionError(0, InstructionError::ProgramFailedToComplete),
- &[],
- Some(vec![
- format!("Program {invoke_program_id} invoke [1]"),
- format!("Program log: invoke {program_lang} program"),
- "Program log: Test max instruction data len exceeded".into(),
- "skip".into(), // don't compare compute consumption logs
- format!(
- "Program {invoke_program_id} failed: Invoked an instruction with data that is \
- too large (10241 > 10240)"
- ),
- ]),
- &bank,
- );
- do_invoke_failure_test_local(
- TEST_MAX_INSTRUCTION_ACCOUNTS_EXCEEDED,
- TransactionError::InstructionError(0, InstructionError::ProgramFailedToComplete),
- &[],
- Some(vec![
- format!("Program {invoke_program_id} invoke [1]"),
- format!("Program log: invoke {program_lang} program"),
- "Program log: Test max instruction accounts exceeded".into(),
- "skip".into(), // don't compare compute consumption logs
- format!(
- "Program {invoke_program_id} failed: Invoked an instruction with too many \
- accounts (256 > 255)"
- ),
- ]),
- &bank,
- );
- do_invoke_failure_test_local(
- TEST_MAX_ACCOUNT_INFOS_EXCEEDED,
- TransactionError::InstructionError(0, InstructionError::ProgramFailedToComplete),
- &[],
- Some(vec![
- format!("Program {invoke_program_id} invoke [1]"),
- format!("Program log: invoke {program_lang} program"),
- "Program log: Test max account infos exceeded".into(),
- "skip".into(), // don't compare compute consumption logs
- format!(
- "Program {invoke_program_id} failed: Invoked an instruction with too many \
- account info's (256 > 255)"
- ),
- ]),
- &bank,
- );
- let bank = bank_with_feature_deactivated(
- &bank_forks,
- bank,
- &feature_set::increase_cpi_account_info_limit::id(),
- );
- assert!(!bank
- .feature_set
- .is_active(&feature_set::increase_cpi_account_info_limit::id()));
- do_invoke_failure_test_local(
- TEST_MAX_ACCOUNT_INFOS_EXCEEDED_BEFORE_SIMD_0339,
- TransactionError::InstructionError(0, InstructionError::ProgramFailedToComplete),
- &[],
- Some(vec![
- format!("Program {invoke_program_id} invoke [1]"),
- format!("Program log: invoke {program_lang} program"),
- "Program log: Test max account infos exceeded before SIMD-0339".into(),
- "skip".into(), // don't compare compute consumption logs
- format!(
- "Program {invoke_program_id} failed: Invoked an instruction with too many \
- account info's (129 > 128)"
- ),
- ]),
- &bank,
- );
- let bank = bank_with_feature_deactivated(
- &bank_forks,
- bank,
- &feature_set::increase_tx_account_lock_limit::id(),
- );
- assert!(!bank
- .feature_set
- .is_active(&feature_set::increase_tx_account_lock_limit::id()));
- do_invoke_failure_test_local(
- TEST_MAX_ACCOUNT_INFOS_EXCEEDED_BEFORE_INCREASE_TX_ACCOUNT_LOCK_BEFORE_SIMD_0339,
- TransactionError::InstructionError(0, InstructionError::ProgramFailedToComplete),
- &[],
- Some(vec![
- format!("Program {invoke_program_id} invoke [1]"),
- format!("Program log: invoke {program_lang} program"),
- "Program log: Test max account infos exceeded before SIMD-0339 and before \
- increase cpi info"
- .into(),
- "skip".into(), // don't compare compute consumption logs
- format!(
- "Program {invoke_program_id} failed: Invoked an instruction with too many \
- account info's (65 > 64)"
- ),
- ]),
- &bank,
- );
- do_invoke_failure_test_local(
- TEST_RETURN_ERROR,
- TransactionError::InstructionError(0, InstructionError::Custom(42)),
- std::slice::from_ref(&invoked_program_id),
- None,
- &bank,
- );
- do_invoke_failure_test_local(
- TEST_PRIVILEGE_DEESCALATION_ESCALATION_SIGNER,
- TransactionError::InstructionError(0, InstructionError::PrivilegeEscalation),
- std::slice::from_ref(&invoked_program_id),
- None,
- &bank,
- );
- do_invoke_failure_test_local(
- TEST_PRIVILEGE_DEESCALATION_ESCALATION_WRITABLE,
- TransactionError::InstructionError(0, InstructionError::PrivilegeEscalation),
- std::slice::from_ref(&invoked_program_id),
- None,
- &bank,
- );
- do_invoke_failure_test_local_with_compute_check(
- TEST_WRITABLE_DEESCALATION_WRITABLE,
- TransactionError::InstructionError(0, InstructionError::ReadonlyDataModified),
- std::slice::from_ref(&invoked_program_id),
- None,
- true, // should_deplete_compute_meter
- &bank,
- );
- // With SIMD-0268 disabled, five nested invokes is too deep.
- let bank = bank_with_feature_deactivated(
- &bank_forks,
- bank,
- &feature_set::raise_cpi_nesting_limit_to_8::id(),
- );
- assert!(!bank
- .feature_set
- .is_active(&feature_set::raise_cpi_nesting_limit_to_8::id()));
- do_invoke_failure_test_local(
- TEST_NESTED_INVOKE_TOO_DEEP,
- TransactionError::InstructionError(0, InstructionError::CallDepth),
- &[
- invoked_program_id.clone(),
- invoked_program_id.clone(),
- invoked_program_id.clone(),
- invoked_program_id.clone(),
- invoked_program_id.clone(),
- ],
- None,
- &bank,
- );
- // With SIMD-0268 enabled, nine nested invokes is too deep.
- let bank = bank_with_feature_activated(
- &bank_forks,
- bank,
- &feature_set::raise_cpi_nesting_limit_to_8::id(),
- );
- assert!(bank
- .feature_set
- .is_active(&feature_set::raise_cpi_nesting_limit_to_8::id()));
- do_invoke_failure_test_local(
- TEST_NESTED_INVOKE_SIMD_0268_TOO_DEEP,
- TransactionError::InstructionError(0, InstructionError::CallDepth),
- &[
- invoked_program_id.clone(),
- invoked_program_id.clone(),
- invoked_program_id.clone(),
- invoked_program_id.clone(),
- invoked_program_id.clone(),
- invoked_program_id.clone(),
- invoked_program_id.clone(),
- invoked_program_id.clone(),
- invoked_program_id.clone(),
- ],
- None,
- &bank,
- );
- do_invoke_failure_test_local(
- TEST_RETURN_DATA_TOO_LARGE,
- TransactionError::InstructionError(0, InstructionError::ProgramFailedToComplete),
- &[],
- None,
- &bank,
- );
- do_invoke_failure_test_local(
- TEST_DUPLICATE_PRIVILEGE_ESCALATION_SIGNER,
- TransactionError::InstructionError(0, InstructionError::PrivilegeEscalation),
- std::slice::from_ref(&invoked_program_id),
- None,
- &bank,
- );
- do_invoke_failure_test_local(
- TEST_DUPLICATE_PRIVILEGE_ESCALATION_WRITABLE,
- TransactionError::InstructionError(0, InstructionError::PrivilegeEscalation),
- std::slice::from_ref(&invoked_program_id),
- None,
- &bank,
- );
- // Check resulting state
- assert_eq!(43, bank.get_balance(&derived_key1));
- let account = bank.get_account(&derived_key1).unwrap();
- assert_eq!(&invoke_program_id, account.owner());
- assert_eq!(
- MAX_PERMITTED_DATA_INCREASE,
- bank.get_account(&derived_key1).unwrap().data().len()
- );
- for i in 0..20 {
- assert_eq!(i as u8, account.data()[i]);
- }
- // Attempt to realloc into unauthorized address space
- let account = AccountSharedData::new(84, 0, &system_program::id());
- bank.store_account(&from_keypair.pubkey(), &account);
- bank.store_account(&derived_key1, &AccountSharedData::default());
- let instruction = Instruction::new_with_bytes(
- invoke_program_id,
- &[
- TEST_ALLOC_ACCESS_VIOLATION,
- bump_seed1,
- bump_seed2,
- bump_seed3,
- ],
- account_metas.clone(),
- );
- let message = Message::new(&[instruction], Some(&mint_pubkey));
- let tx = Transaction::new(
- &[
- &mint_keypair,
- &argument_keypair,
- &invoked_argument_keypair,
- &from_keypair,
- ],
- message.clone(),
- bank.last_blockhash(),
- );
- let (result, inner_instructions, _log_messages, _executed_units) =
- process_transaction_and_record_inner(&bank, tx);
- let invoked_programs: Vec<Pubkey> = inner_instructions[0]
- .iter()
- .map(|ix| &message.account_keys[ix.instruction.program_id_index as usize])
- .cloned()
- .collect();
- assert_eq!(invoked_programs, vec![]);
- assert_eq!(
- result.unwrap_err(),
- TransactionError::InstructionError(0, InstructionError::ProgramFailedToComplete)
- );
- }
- }
- #[test]
- #[cfg(feature = "sbf_rust")]
- fn test_program_sbf_program_id_spoofing() {
- let GenesisConfigInfo {
- genesis_config,
- mint_keypair,
- ..
- } = create_genesis_config(50);
- let (bank, bank_forks) = Bank::new_with_bank_forks_for_tests(&genesis_config);
- let mut bank_client = BankClient::new_shared(bank.clone());
- let authority_keypair = Keypair::new();
- let (_bank, malicious_swap_pubkey) = load_program_of_loader_v4(
- &mut bank_client,
- &bank_forks,
- &mint_keypair,
- &authority_keypair,
- "solana_sbf_rust_spoof1",
- );
- let (bank, malicious_system_pubkey) = load_program_of_loader_v4(
- &mut bank_client,
- &bank_forks,
- &mint_keypair,
- &authority_keypair,
- "solana_sbf_rust_spoof1_system",
- );
- let from_pubkey = Pubkey::new_unique();
- let account = AccountSharedData::new(10, 0, &system_program::id());
- bank.store_account(&from_pubkey, &account);
- let to_pubkey = Pubkey::new_unique();
- let account = AccountSharedData::new(0, 0, &system_program::id());
- bank.store_account(&to_pubkey, &account);
- let account_metas = vec![
- AccountMeta::new_readonly(system_program::id(), false),
- AccountMeta::new_readonly(malicious_system_pubkey, false),
- AccountMeta::new(from_pubkey, false),
- AccountMeta::new(to_pubkey, false),
- ];
- let instruction =
- Instruction::new_with_bytes(malicious_swap_pubkey, &[], account_metas.clone());
- let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
- assert_eq!(
- result.unwrap_err().unwrap(),
- TransactionError::InstructionError(0, InstructionError::MissingRequiredSignature)
- );
- assert_eq!(10, bank.get_balance(&from_pubkey));
- assert_eq!(0, bank.get_balance(&to_pubkey));
- }
- #[test]
- #[cfg(feature = "sbf_rust")]
- fn test_program_sbf_caller_has_access_to_cpi_program() {
- let GenesisConfigInfo {
- genesis_config,
- mint_keypair,
- ..
- } = create_genesis_config(50);
- let (bank, bank_forks) = Bank::new_with_bank_forks_for_tests(&genesis_config);
- let mut bank_client = BankClient::new_shared(bank.clone());
- let authority_keypair = Keypair::new();
- let (_bank, caller_pubkey) = load_program_of_loader_v4(
- &mut bank_client,
- &bank_forks,
- &mint_keypair,
- &authority_keypair,
- "solana_sbf_rust_caller_access",
- );
- let (_bank, caller2_pubkey) = load_program_of_loader_v4(
- &mut bank_client,
- &bank_forks,
- &mint_keypair,
- &authority_keypair,
- "solana_sbf_rust_caller_access",
- );
- let account_metas = vec![
- AccountMeta::new_readonly(caller_pubkey, false),
- AccountMeta::new_readonly(caller2_pubkey, false),
- ];
- let instruction = Instruction::new_with_bytes(caller_pubkey, &[1], account_metas.clone());
- let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
- assert_eq!(
- result.unwrap_err().unwrap(),
- TransactionError::InstructionError(0, InstructionError::MissingAccount),
- );
- }
- #[test]
- #[cfg(feature = "sbf_rust")]
- fn test_program_sbf_ro_modify() {
- agave_logger::setup();
- let GenesisConfigInfo {
- genesis_config,
- mint_keypair,
- ..
- } = create_genesis_config(50);
- let (bank, bank_forks) = Bank::new_with_bank_forks_for_tests(&genesis_config);
- let mut bank_client = BankClient::new_shared(bank.clone());
- let authority_keypair = Keypair::new();
- let (bank, program_pubkey) = load_program_of_loader_v4(
- &mut bank_client,
- &bank_forks,
- &mint_keypair,
- &authority_keypair,
- "solana_sbf_rust_ro_modify",
- );
- let test_keypair = Keypair::new();
- let account = AccountSharedData::new(10, 0, &system_program::id());
- bank.store_account(&test_keypair.pubkey(), &account);
- let account_metas = vec![
- AccountMeta::new_readonly(system_program::id(), false),
- AccountMeta::new(test_keypair.pubkey(), true),
- ];
- let instruction = Instruction::new_with_bytes(program_pubkey, &[1], account_metas.clone());
- let message = Message::new(&[instruction], Some(&mint_keypair.pubkey()));
- let result = bank_client.send_and_confirm_message(&[&mint_keypair, &test_keypair], message);
- assert_eq!(
- result.unwrap_err().unwrap(),
- TransactionError::InstructionError(0, InstructionError::ProgramFailedToComplete)
- );
- let instruction = Instruction::new_with_bytes(program_pubkey, &[3], account_metas.clone());
- let message = Message::new(&[instruction], Some(&mint_keypair.pubkey()));
- let result = bank_client.send_and_confirm_message(&[&mint_keypair, &test_keypair], message);
- assert_eq!(
- result.unwrap_err().unwrap(),
- TransactionError::InstructionError(0, InstructionError::ProgramFailedToComplete)
- );
- let instruction = Instruction::new_with_bytes(program_pubkey, &[4], account_metas.clone());
- let message = Message::new(&[instruction], Some(&mint_keypair.pubkey()));
- let result = bank_client.send_and_confirm_message(&[&mint_keypair, &test_keypair], message);
- assert_eq!(
- result.unwrap_err().unwrap(),
- TransactionError::InstructionError(0, InstructionError::ProgramFailedToComplete)
- );
- }
- #[test]
- #[cfg(feature = "sbf_rust")]
- fn test_program_sbf_call_depth() {
- agave_logger::setup();
- let GenesisConfigInfo {
- genesis_config,
- mint_keypair,
- ..
- } = create_genesis_config(50);
- let (bank, bank_forks) = Bank::new_with_bank_forks_for_tests(&genesis_config);
- let mut bank_client = BankClient::new_shared(bank);
- let authority_keypair = Keypair::new();
- let (_bank, program_id) = load_program_of_loader_v4(
- &mut bank_client,
- &bank_forks,
- &mint_keypair,
- &authority_keypair,
- "solana_sbf_rust_call_depth",
- );
- let budget = ComputeBudget::new_with_defaults(
- genesis_config
- .accounts
- .contains_key(&feature_set::raise_cpi_nesting_limit_to_8::id()),
- genesis_config
- .accounts
- .contains_key(&feature_set::increase_cpi_account_info_limit::id()),
- );
- let instruction =
- Instruction::new_with_bincode(program_id, &(budget.max_call_depth - 1), vec![]);
- let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
- assert!(result.is_ok());
- let instruction = Instruction::new_with_bincode(program_id, &budget.max_call_depth, vec![]);
- let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
- assert!(result.is_err());
- }
- #[test]
- #[cfg(feature = "sbf_rust")]
- fn test_program_sbf_compute_budget() {
- agave_logger::setup();
- let GenesisConfigInfo {
- genesis_config,
- mint_keypair,
- ..
- } = create_genesis_config(50);
- let (bank, bank_forks) = Bank::new_with_bank_forks_for_tests(&genesis_config);
- let mut bank_client = BankClient::new_shared(bank);
- let authority_keypair = Keypair::new();
- let (_bank, program_id) = load_program_of_loader_v4(
- &mut bank_client,
- &bank_forks,
- &mint_keypair,
- &authority_keypair,
- "solana_sbf_rust_noop",
- );
- let message = Message::new(
- &[
- ComputeBudgetInstruction::set_compute_unit_limit(150),
- Instruction::new_with_bincode(program_id, &0, vec![]),
- ],
- Some(&mint_keypair.pubkey()),
- );
- let result = bank_client.send_and_confirm_message(&[&mint_keypair], message);
- assert_eq!(
- result.unwrap_err().unwrap(),
- TransactionError::InstructionError(1, InstructionError::ProgramFailedToComplete),
- );
- }
- #[test]
- fn assert_instruction_count() {
- agave_logger::setup();
- let mut programs = Vec::new();
- #[cfg(feature = "sbf_c")]
- {
- programs.extend_from_slice(&[
- ("alloc", 18572),
- ("sbf_to_sbf", 316),
- ("multiple_static", 210),
- ("noop", 5),
- ("noop++", 5),
- ("relative_call", 212),
- ("return_data", 1026),
- ("sanity", 2371),
- ("sanity++", 2271),
- ("secp256k1_recover", 25421),
- ("sha", 1446),
- ("struct_pass", 108),
- ("struct_ret", 122),
- ]);
- }
- #[cfg(feature = "sbf_rust")]
- {
- programs.extend_from_slice(&[
- ("solana_sbf_rust_128bit", 784),
- ("solana_sbf_rust_alloc", 4934),
- ("solana_sbf_rust_custom_heap", 343),
- ("solana_sbf_rust_dep_crate", 22),
- ("solana_sbf_rust_iter", 1514),
- ("solana_sbf_rust_many_args", 1287),
- ("solana_sbf_rust_mem", 1326),
- ("solana_sbf_rust_membuiltins", 329),
- ("solana_sbf_rust_noop", 342),
- ("solana_sbf_rust_param_passing", 108),
- ("solana_sbf_rust_rand", 315),
- ("solana_sbf_rust_sanity", 14223),
- ("solana_sbf_rust_secp256k1_recover", 88615),
- ("solana_sbf_rust_sha", 21998),
- ]);
- }
- println!("\n {:36} expected actual diff", "SBF program");
- for (program_name, expected_consumption) in programs.iter() {
- let loader_id = bpf_loader::id();
- let program_key = Pubkey::new_unique();
- let mut transaction_accounts = vec![
- (program_key, AccountSharedData::new(0, 0, &loader_id)),
- (
- Pubkey::new_unique(),
- AccountSharedData::new(0, 0, &program_key),
- ),
- ];
- let instruction_accounts = vec![AccountMeta {
- pubkey: transaction_accounts[1].0,
- is_signer: false,
- is_writable: false,
- }];
- transaction_accounts[0]
- .1
- .set_data_from_slice(&load_program_from_file(program_name));
- transaction_accounts[0].1.set_executable(true);
- let prev_compute_meter = RefCell::new(0);
- print!(" {:36} {:8}", program_name, *expected_consumption);
- mock_process_instruction(
- &loader_id,
- Some(0),
- &[],
- transaction_accounts,
- instruction_accounts,
- Ok(()),
- solana_bpf_loader_program::Entrypoint::vm,
- |invoke_context| {
- *prev_compute_meter.borrow_mut() = invoke_context.get_remaining();
- solana_bpf_loader_program::test_utils::load_all_invoked_programs(invoke_context);
- },
- |invoke_context| {
- let consumption = prev_compute_meter
- .borrow()
- .saturating_sub(invoke_context.get_remaining());
- let diff: i64 = consumption as i64 - *expected_consumption as i64;
- println!(
- "{:6} {:+5} ({:+3.0}%)",
- consumption,
- diff,
- 100.0_f64 * consumption as f64 / *expected_consumption as f64 - 100.0_f64,
- );
- assert!(consumption <= *expected_consumption);
- },
- );
- }
- }
- #[test]
- #[cfg(feature = "sbf_rust")]
- fn test_program_sbf_instruction_introspection() {
- agave_logger::setup();
- let GenesisConfigInfo {
- genesis_config,
- mint_keypair,
- ..
- } = create_genesis_config(50_000);
- let (bank, bank_forks) = Bank::new_with_bank_forks_for_tests(&genesis_config);
- let mut bank_client = BankClient::new_shared(bank.clone());
- let authority_keypair = Keypair::new();
- let (_bank, program_id) = load_program_of_loader_v4(
- &mut bank_client,
- &bank_forks,
- &mint_keypair,
- &authority_keypair,
- "solana_sbf_rust_instruction_introspection",
- );
- // Passing transaction
- let account_metas = vec![
- AccountMeta::new_readonly(program_id, false),
- AccountMeta::new_readonly(sysvar::instructions::id(), false),
- ];
- let instruction0 = Instruction::new_with_bytes(program_id, &[0u8, 0u8], account_metas.clone());
- let instruction1 = Instruction::new_with_bytes(program_id, &[0u8, 1u8], account_metas.clone());
- let instruction2 = Instruction::new_with_bytes(program_id, &[0u8, 2u8], account_metas);
- let message = Message::new(
- &[instruction0, instruction1, instruction2],
- Some(&mint_keypair.pubkey()),
- );
- let result = bank_client.send_and_confirm_message(&[&mint_keypair], message);
- assert!(result.is_ok());
- // writable special instructions11111 key, should not be allowed
- let account_metas = vec![AccountMeta::new(sysvar::instructions::id(), false)];
- let instruction = Instruction::new_with_bytes(program_id, &[0], account_metas);
- let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
- assert_eq!(
- result.unwrap_err().unwrap(),
- // sysvar write locks are demoted to read only. So this will no longer
- // cause InvalidAccountIndex error.
- TransactionError::InstructionError(0, InstructionError::ProgramFailedToComplete),
- );
- // No accounts, should error
- let instruction = Instruction::new_with_bytes(program_id, &[0], vec![]);
- let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
- #[allow(deprecated)]
- let expected_error =
- TransactionError::InstructionError(0, InstructionError::NotEnoughAccountKeys);
- assert!(result.is_err());
- assert_eq!(result.unwrap_err().unwrap(), expected_error,);
- assert!(bank.get_account(&sysvar::instructions::id()).is_none());
- }
- #[test_matrix(
- [0, 1, 2, 5, 10, 15, 20],
- [1, 10, 50, 100, 255, 500, 1000, 1024] // MAX_RETURN_DATA = 1024
- )]
- #[allow(clippy::arithmetic_side_effects)]
- #[cfg(feature = "sbf_rust")]
- fn test_program_sbf_r2_instruction_data_pointer(num_accounts: usize, input_data_len: usize) {
- agave_logger::setup();
- let GenesisConfigInfo {
- genesis_config,
- mint_keypair,
- ..
- } = create_genesis_config(50);
- let (bank, bank_forks) = Bank::new_with_bank_forks_for_tests(&genesis_config);
- let mut bank_client = BankClient::new_shared(bank.clone());
- let authority_keypair = Keypair::new();
- let (bank, program_id) = load_program_of_loader_v4(
- &mut bank_client,
- &bank_forks,
- &mint_keypair,
- &authority_keypair,
- "solana_sbf_rust_r2_instruction_data_pointer",
- );
- let mut account_metas = Vec::new();
- for i in 0..num_accounts {
- let pubkey = Pubkey::new_unique();
- // Mixed account sizes.
- bank.store_account(
- &pubkey,
- &AccountSharedData::new(0, 100 + (i * 50), &program_id),
- );
- // Mixed account roles.
- if i % 2 == 0 {
- account_metas.push(AccountMeta::new(pubkey, false));
- } else {
- account_metas.push(AccountMeta::new_readonly(pubkey, false));
- }
- }
- bank.freeze();
- // The provided instruction data will be set to the return data.
- let input_data: Vec<u8> = (0..input_data_len).map(|i| (i % 256) as u8).collect();
- let instruction = Instruction::new_with_bytes(program_id, &input_data, account_metas);
- let blockhash = bank.last_blockhash();
- let message = Message::new(&[instruction], Some(&mint_keypair.pubkey()));
- let transaction = Transaction::new(&[&mint_keypair], message, blockhash);
- let sanitized_tx = RuntimeTransaction::from_transaction_for_tests(transaction);
- let result = bank.simulate_transaction(&sanitized_tx, false);
- assert!(result.result.is_ok());
- let return_data = result.return_data.unwrap().data;
- assert_eq!(input_data, return_data);
- }
- fn get_stable_genesis_config() -> GenesisConfigInfo {
- let validator_pubkey =
- Pubkey::from_str("GLh546CXmtZdvpEzL8sxzqhhUf7KPvmGaRpFHB5W1sjV").unwrap();
- let mint_keypair = Keypair::from_base58_string(
- "4YTH9JSRgZocmK9ezMZeJCCV2LVeR2NatTBA8AFXkg2x83fqrt8Vwyk91961E7ns4vee9yUBzuDfztb8i9iwTLFd",
- );
- let voting_keypair = Keypair::from_base58_string(
- "4EPWEn72zdNY1JSKkzyZ2vTZcKdPW3jM5WjAgUadnoz83FR5cDFApbo7s5mwBcYXn8afVe2syReJaqBi4fkhG3mH",
- );
- let stake_pubkey = Pubkey::from_str("HGq9JF77xFXRgWRJy8VQuhdbdugrT856RvQDzr1KJo6E").unwrap();
- let mut genesis_config = create_genesis_config_with_leader_ex(
- 123,
- &mint_keypair.pubkey(),
- &validator_pubkey,
- &voting_keypair.pubkey(),
- &stake_pubkey,
- None,
- bootstrap_validator_stake_lamports(),
- 42,
- FeeRateGovernor::new(0, 0), // most tests can't handle transaction fees
- Rent::free(), // most tests don't expect rent
- ClusterType::Development,
- vec![],
- );
- genesis_config.creation_time = Duration::ZERO.as_secs() as UnixTimestamp;
- GenesisConfigInfo {
- genesis_config,
- mint_keypair,
- voting_keypair,
- validator_pubkey,
- }
- }
- #[test]
- #[ignore]
- #[cfg(feature = "sbf_rust")]
- fn test_program_sbf_invoke_stable_genesis_and_bank() {
- // The purpose of this test is to exercise various code branches of runtime/VM and
- // assert that the resulting bank hash matches with the expected value.
- // The assert check is commented out by default. Please refer to the last few lines
- // of the test to enable the assertion.
- agave_logger::setup();
- let GenesisConfigInfo {
- genesis_config,
- mint_keypair,
- ..
- } = get_stable_genesis_config();
- let bank = Bank::new_for_tests(&genesis_config);
- let bank = Arc::new(bank);
- let bank_client = BankClient::new_shared(bank.clone());
- // Deploy upgradeable program
- let buffer_keypair = Keypair::from_base58_string(
- "4q4UvWxh2oMifTGbChDeWCbdN8eJEUQ1E6cuNnmymJ6AN5CMUT2VW5A1RKnG9dy7ypLczB9inMUAafh5TkpXrtxg",
- );
- let program_keypair = Keypair::from_base58_string(
- "3LQpBxgpaFNJPit5a8t51pJKMkUmNUn5PhSTcuuhuuBxe43cTeqVPhMtKkFNr5VpFzCExf4ihibvuZgGxmjy6t8n",
- );
- let program_id = program_keypair.pubkey();
- let authority_keypair = Keypair::from_base58_string(
- "285XFW2NTWd6CMvtHzvYYS1kWzmzcGBnyEXbH1v8hq6YJqJsLMTYMPkbEQqeE7m7UqhoMeK5V3HMJLf9DdxwU2Gy",
- );
- let instruction =
- Instruction::new_with_bytes(program_id, &[0], vec![AccountMeta::new(clock::id(), false)]);
- // Call program before its deployed
- let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction.clone());
- assert_eq!(
- result.unwrap_err().unwrap(),
- TransactionError::ProgramAccountNotFound
- );
- #[allow(deprecated)]
- solana_runtime::loader_utils::load_upgradeable_program(
- &bank_client,
- &mint_keypair,
- &buffer_keypair,
- &program_keypair,
- &authority_keypair,
- "solana_sbf_rust_noop",
- );
- // Deploy indirect invocation program
- let indirect_program_keypair = Keypair::from_base58_string(
- "2BgE4gD5wUCwiAVPYbmWd2xzXSsD9W2fWgNjwmVkm8WL7i51vK9XAXNnX1VB6oKQZmjaUPRd5RzE6RggB9DeKbZC",
- );
- #[allow(deprecated)]
- solana_runtime::loader_utils::load_upgradeable_program(
- &bank_client,
- &mint_keypair,
- &buffer_keypair,
- &indirect_program_keypair,
- &authority_keypair,
- "solana_sbf_rust_invoke_and_return",
- );
- let invoke_instruction =
- Instruction::new_with_bytes(program_id, &[0], vec![AccountMeta::new(clock::id(), false)]);
- let indirect_invoke_instruction = Instruction::new_with_bytes(
- indirect_program_keypair.pubkey(),
- &[0],
- vec![
- AccountMeta::new_readonly(program_id, false),
- AccountMeta::new_readonly(clock::id(), false),
- ],
- );
- // Prepare redeployment
- let buffer_keypair = Keypair::from_base58_string(
- "5T5L31FiUphXh4N6mxiWhEKPrdLhvMJSbaHo1Ne7zZYkw6YT1fVkqsWdA6pHMtqATiMTc4sfx5yTV9M9AnWDoBkW",
- );
- load_upgradeable_buffer(
- &bank_client,
- &mint_keypair,
- &buffer_keypair,
- &authority_keypair,
- "solana_sbf_rust_panic",
- );
- let redeployment_instruction = loader_v3_instruction::upgrade(
- &program_id,
- &buffer_keypair.pubkey(),
- &authority_keypair.pubkey(),
- &mint_keypair.pubkey(),
- );
- // Redeployment causes programs to be unavailable to both top-level-instructions and CPI instructions
- for invoke_instruction in [invoke_instruction, indirect_invoke_instruction] {
- // Call upgradeable program
- let result =
- bank_client.send_and_confirm_instruction(&mint_keypair, invoke_instruction.clone());
- assert!(result.is_ok());
- // Upgrade the program and invoke in same tx
- let message = Message::new(
- &[redeployment_instruction.clone(), invoke_instruction],
- Some(&mint_keypair.pubkey()),
- );
- let tx = Transaction::new(
- &[&mint_keypair, &authority_keypair],
- message.clone(),
- bank.last_blockhash(),
- );
- let (result, _, _, _) = process_transaction_and_record_inner(&bank, tx);
- assert_eq!(
- result.unwrap_err(),
- TransactionError::InstructionError(1, InstructionError::InvalidAccountData),
- );
- }
- // Prepare undeployment
- let (programdata_address, _) = Pubkey::find_program_address(
- &[program_keypair.pubkey().as_ref()],
- &bpf_loader_upgradeable::id(),
- );
- let undeployment_instruction = loader_v3_instruction::close_any(
- &programdata_address,
- &mint_keypair.pubkey(),
- Some(&authority_keypair.pubkey()),
- Some(&program_id),
- );
- let invoke_instruction =
- Instruction::new_with_bytes(program_id, &[1], vec![AccountMeta::new(clock::id(), false)]);
- let indirect_invoke_instruction = Instruction::new_with_bytes(
- indirect_program_keypair.pubkey(),
- &[1],
- vec![
- AccountMeta::new_readonly(program_id, false),
- AccountMeta::new_readonly(clock::id(), false),
- ],
- );
- // Undeployment is visible to both top-level-instructions and CPI instructions
- for invoke_instruction in [invoke_instruction, indirect_invoke_instruction] {
- // Call upgradeable program
- let result =
- bank_client.send_and_confirm_instruction(&mint_keypair, invoke_instruction.clone());
- assert!(result.is_ok());
- // Undeploy the program and invoke in same tx
- let message = Message::new(
- &[undeployment_instruction.clone(), invoke_instruction],
- Some(&mint_keypair.pubkey()),
- );
- let tx = Transaction::new(
- &[&mint_keypair, &authority_keypair],
- message.clone(),
- bank.last_blockhash(),
- );
- let (result, _, _, _) = process_transaction_and_record_inner(&bank, tx);
- assert_eq!(
- result.unwrap_err(),
- TransactionError::InstructionError(1, InstructionError::InvalidAccountData),
- );
- }
- bank.freeze();
- let expected_hash = Hash::from_str("2A2vqbUKExRbnaAzSnDFXdsBZRZSpCjGZCAA3mFZG2sV")
- .expect("Failed to generate hash");
- println!("Stable test produced bank hash: {}", bank.hash());
- println!("Expected hash: {}", expected_hash);
- // Enable the following code to match the bank hash with the expected bank hash.
- // Follow these steps.
- // 1. Run this test on the baseline/master commit, and get the expected bank hash.
- // 2. Update the `expected_hash` to match the expected bank hash.
- // 3. Run the test in the PR branch that's being tested.
- // If the hash doesn't match, the PR likely has runtime changes that can lead to
- // consensus failure.
- // assert_eq!(bank.hash(), expected_hash);
- }
- #[test]
- #[cfg(feature = "sbf_rust")]
- fn test_program_sbf_invoke_in_same_tx_as_deployment() {
- agave_logger::setup();
- let GenesisConfigInfo {
- genesis_config,
- mint_keypair,
- ..
- } = create_genesis_config(50);
- let (bank, bank_forks) = Bank::new_with_bank_forks_for_tests(&genesis_config);
- let mut bank_client = BankClient::new_shared(bank.clone());
- // Deploy upgradeable program
- let authority_keypair = Keypair::new();
- let (program_keypair, deployment_instructions) = instructions_to_load_program_of_loader_v4(
- &bank_client,
- &mint_keypair,
- &authority_keypair,
- "solana_sbf_rust_noop",
- None,
- None,
- );
- let program_id = program_keypair.pubkey();
- // Deploy indirect invocation program
- let (bank, indirect_program_id) = load_program_of_loader_v4(
- &mut bank_client,
- &bank_forks,
- &mint_keypair,
- &authority_keypair,
- "solana_sbf_rust_invoke_and_return",
- );
- // Prepare invocations
- let invoke_instruction =
- Instruction::new_with_bytes(program_id, &[0], vec![AccountMeta::new(clock::id(), false)]);
- let indirect_invoke_instruction = Instruction::new_with_bytes(
- indirect_program_id,
- &[0],
- vec![
- AccountMeta::new_readonly(program_id, false),
- AccountMeta::new_readonly(clock::id(), false),
- ],
- );
- // Deployment is invisible to both top-level-instructions and CPI instructions
- for (index, invoke_instruction) in [invoke_instruction, indirect_invoke_instruction]
- .into_iter()
- .enumerate()
- {
- let mut instructions = deployment_instructions.clone();
- instructions.push(invoke_instruction);
- let tx = Transaction::new(
- &[&mint_keypair, &program_keypair, &authority_keypair],
- Message::new(&instructions, Some(&mint_keypair.pubkey())),
- bank.last_blockhash(),
- );
- if index == 0 {
- let result = load_execute_and_commit_transaction(&bank, tx);
- assert_eq!(
- result.unwrap().status,
- Err(TransactionError::ProgramAccountNotFound),
- );
- } else {
- let (result, _, _, _) = process_transaction_and_record_inner(&bank, tx);
- if let TransactionError::InstructionError(instr_no, ty) = result.unwrap_err() {
- // Asserting the instruction number as an upper bound, since the quantity of
- // instructions depends on the program size, which in turn depends on the SBPF
- // versions.
- assert!(instr_no <= 40);
- assert_eq!(ty, InstructionError::UnsupportedProgramId);
- } else {
- panic!("Invalid error type");
- }
- }
- }
- }
- #[test]
- #[cfg(feature = "sbf_rust")]
- fn test_program_sbf_invoke_in_same_tx_as_redeployment() {
- agave_logger::setup();
- let GenesisConfigInfo {
- genesis_config,
- mint_keypair,
- ..
- } = create_genesis_config(50);
- let (bank, bank_forks) = Bank::new_with_bank_forks_for_tests(&genesis_config);
- let mut bank_client = BankClient::new_shared(bank.clone());
- // Deploy upgradeable program
- let authority_keypair = Keypair::new();
- let (_bank, program_id) = load_program_of_loader_v4(
- &mut bank_client,
- &bank_forks,
- &mint_keypair,
- &authority_keypair,
- "solana_sbf_rust_noop",
- );
- let (source_program_keypair, mut deployment_instructions) =
- instructions_to_load_program_of_loader_v4(
- &bank_client,
- &mint_keypair,
- &authority_keypair,
- "solana_sbf_rust_panic",
- None,
- Some(&program_id),
- );
- let undeployment_instruction =
- loader_v4_instruction::retract(&program_id, &authority_keypair.pubkey());
- let redeployment_instructions =
- deployment_instructions.split_off(deployment_instructions.len() - 3);
- let signers: &[&[&Keypair]] = &[
- &[&mint_keypair, &source_program_keypair],
- &[&mint_keypair, &authority_keypair],
- ];
- let signers = std::iter::once(signers[0]).chain(std::iter::repeat(signers[1]));
- for (instruction, signers) in deployment_instructions.into_iter().zip(signers) {
- let message = Message::new(&[instruction], Some(&mint_keypair.pubkey()));
- bank_client
- .send_and_confirm_message(signers, message)
- .unwrap();
- }
- // Deploy indirect invocation program
- let (bank, indirect_program_id) = load_program_of_loader_v4(
- &mut bank_client,
- &bank_forks,
- &mint_keypair,
- &authority_keypair,
- "solana_sbf_rust_invoke_and_return",
- );
- // Prepare invocations
- let invoke_instruction =
- Instruction::new_with_bytes(program_id, &[0], vec![AccountMeta::new(clock::id(), false)]);
- let indirect_invoke_instruction = Instruction::new_with_bytes(
- indirect_program_id,
- &[0],
- vec![
- AccountMeta::new_readonly(program_id, false),
- AccountMeta::new_readonly(clock::id(), false),
- ],
- );
- // Redeployment fails when top-level-instructions invoke the program because of write lock demotion
- // and the program becomes unavailable to CPI instructions
- for (invoke_instruction, expected_error) in [
- (
- invoke_instruction,
- TransactionError::InstructionError(0, InstructionError::InvalidArgument),
- ),
- (
- indirect_invoke_instruction,
- TransactionError::InstructionError(4, InstructionError::UnsupportedProgramId),
- ),
- ] {
- // Call upgradeable program
- let result =
- bank_client.send_and_confirm_instruction(&mint_keypair, invoke_instruction.clone());
- assert!(result.is_ok());
- // Upgrade the program and invoke in same tx
- let message = Message::new(
- &[
- undeployment_instruction.clone(),
- redeployment_instructions[0].clone(),
- redeployment_instructions[1].clone(),
- redeployment_instructions[2].clone(),
- invoke_instruction,
- ],
- Some(&mint_keypair.pubkey()),
- );
- let tx = Transaction::new(
- &[&mint_keypair, &authority_keypair],
- message.clone(),
- bank.last_blockhash(),
- );
- let (result, _, _, _) = process_transaction_and_record_inner(&bank, tx);
- assert_eq!(result.unwrap_err(), expected_error,);
- }
- }
- #[test]
- #[cfg(feature = "sbf_rust")]
- fn test_program_sbf_invoke_in_same_tx_as_undeployment() {
- agave_logger::setup();
- let GenesisConfigInfo {
- genesis_config,
- mint_keypair,
- ..
- } = create_genesis_config(50);
- let (bank, bank_forks) = Bank::new_with_bank_forks_for_tests(&genesis_config);
- let mut bank_client = BankClient::new_shared(bank.clone());
- // Deploy upgradeable program
- let authority_keypair = Keypair::new();
- let (_bank, program_id) = load_program_of_loader_v4(
- &mut bank_client,
- &bank_forks,
- &mint_keypair,
- &authority_keypair,
- "solana_sbf_rust_noop",
- );
- // Deploy indirect invocation program
- let (bank, indirect_program_id) = load_program_of_loader_v4(
- &mut bank_client,
- &bank_forks,
- &mint_keypair,
- &authority_keypair,
- "solana_sbf_rust_invoke_and_return",
- );
- // Prepare invocations
- let invoke_instruction =
- Instruction::new_with_bytes(program_id, &[0], vec![AccountMeta::new(clock::id(), false)]);
- let indirect_invoke_instruction = Instruction::new_with_bytes(
- indirect_program_id,
- &[0],
- vec![
- AccountMeta::new_readonly(program_id, false),
- AccountMeta::new_readonly(clock::id(), false),
- ],
- );
- // Prepare undeployment
- let undeployment_instruction =
- loader_v4_instruction::retract(&program_id, &authority_keypair.pubkey());
- // Undeployment fails when top-level-instructions invoke the program because of write lock demotion
- // and the program becomes unavailable to CPI instructions
- for (invoke_instruction, expected_error) in [
- (
- invoke_instruction,
- TransactionError::InstructionError(0, InstructionError::InvalidArgument),
- ),
- (
- indirect_invoke_instruction,
- TransactionError::InstructionError(1, InstructionError::UnsupportedProgramId),
- ),
- ] {
- // Call upgradeable program
- let result =
- bank_client.send_and_confirm_instruction(&mint_keypair, invoke_instruction.clone());
- assert!(result.is_ok());
- // Upgrade the program and invoke in same tx
- let message = Message::new(
- &[undeployment_instruction.clone(), invoke_instruction],
- Some(&mint_keypair.pubkey()),
- );
- let tx = Transaction::new(
- &[&mint_keypair, &authority_keypair],
- message.clone(),
- bank.last_blockhash(),
- );
- let (result, _, _, _) = process_transaction_and_record_inner(&bank, tx);
- assert_eq!(result.unwrap_err(), expected_error,);
- }
- }
- #[test]
- #[cfg(any(feature = "sbf_c", feature = "sbf_rust"))]
- fn test_program_sbf_disguised_as_sbf_loader() {
- agave_logger::setup();
- let mut programs = Vec::new();
- #[cfg(feature = "sbf_c")]
- {
- programs.extend_from_slice(&[("noop")]);
- }
- #[cfg(feature = "sbf_rust")]
- {
- programs.extend_from_slice(&[("solana_sbf_rust_noop")]);
- }
- for program in programs.iter() {
- let GenesisConfigInfo {
- genesis_config,
- mint_keypair,
- ..
- } = create_genesis_config(50);
- let mut bank = Bank::new_for_tests(&genesis_config);
- bank.deactivate_feature(&agave_feature_set::remove_bpf_loader_incorrect_program_id::id());
- let (bank, bank_forks) = bank.wrap_with_bank_forks_for_tests();
- let mut bank_client = BankClient::new_shared(bank);
- let authority_keypair = Keypair::new();
- let (_bank, program_id) = load_program_of_loader_v4(
- &mut bank_client,
- &bank_forks,
- &mint_keypair,
- &authority_keypair,
- program,
- );
- let account_metas = vec![AccountMeta::new_readonly(program_id, false)];
- let instruction = Instruction::new_with_bytes(bpf_loader::id(), &[1], account_metas);
- let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
- assert_eq!(
- result.unwrap_err().unwrap(),
- TransactionError::InstructionError(0, InstructionError::UnsupportedProgramId)
- );
- }
- }
- #[test]
- #[cfg(feature = "sbf_c")]
- fn test_program_reads_from_program_account() {
- use solana_loader_v4_interface::state as loader_v4_state;
- agave_logger::setup();
- let GenesisConfigInfo {
- genesis_config,
- mint_keypair,
- ..
- } = create_genesis_config(50);
- let (bank, bank_forks) = Bank::new_with_bank_forks_for_tests(&genesis_config);
- let mut bank_client = BankClient::new_shared(bank);
- let authority_keypair = Keypair::new();
- let (_bank, program_id) = load_program_of_loader_v4(
- &mut bank_client,
- &bank_forks,
- &mint_keypair,
- &authority_keypair,
- "read_program",
- );
- let data = bank_client.get_account_data(&program_id).unwrap().unwrap();
- let account_metas = vec![AccountMeta::new_readonly(program_id, false)];
- let instruction = Instruction::new_with_bytes(
- program_id,
- &data[0..loader_v4_state::LoaderV4State::program_data_offset()],
- account_metas,
- );
- bank_client
- .send_and_confirm_instruction(&mint_keypair, instruction)
- .unwrap();
- }
- #[test]
- #[cfg(feature = "sbf_c")]
- fn test_program_sbf_c_dup() {
- agave_logger::setup();
- let GenesisConfigInfo {
- genesis_config,
- mint_keypair,
- ..
- } = create_genesis_config(50);
- let (bank, bank_forks) = Bank::new_with_bank_forks_for_tests(&genesis_config);
- let account_address = Pubkey::new_unique();
- let account = AccountSharedData::new_data(42, &[1_u8, 2, 3], &system_program::id()).unwrap();
- bank.store_account(&account_address, &account);
- let mut bank_client = BankClient::new_shared(bank);
- let authority_keypair = Keypair::new();
- let (_bank, program_id) = load_program_of_loader_v4(
- &mut bank_client,
- &bank_forks,
- &mint_keypair,
- &authority_keypair,
- "ser",
- );
- let account_metas = vec![
- AccountMeta::new_readonly(account_address, false),
- AccountMeta::new_readonly(account_address, false),
- ];
- let instruction = Instruction::new_with_bytes(program_id, &[4, 5, 6, 7], account_metas);
- bank_client
- .send_and_confirm_instruction(&mint_keypair, instruction)
- .unwrap();
- }
- #[test]
- #[cfg(feature = "sbf_rust")]
- fn test_program_sbf_upgrade() {
- agave_logger::setup();
- let GenesisConfigInfo {
- genesis_config,
- mint_keypair,
- ..
- } = create_genesis_config(50);
- let (bank, bank_forks) = Bank::new_with_bank_forks_for_tests(&genesis_config);
- let mut bank_client = BankClient::new_shared(bank);
- // Deploy upgrade program
- let authority_keypair = Keypair::new();
- let (_bank, program_id) = load_program_of_loader_v4(
- &mut bank_client,
- &bank_forks,
- &mint_keypair,
- &authority_keypair,
- "solana_sbf_rust_upgradeable",
- );
- // Call upgradeable program
- let mut instruction =
- Instruction::new_with_bytes(program_id, &[0], vec![AccountMeta::new(clock::id(), false)]);
- let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction.clone());
- assert_eq!(
- result.unwrap_err().unwrap(),
- TransactionError::InstructionError(0, InstructionError::Custom(42))
- );
- // Set authority
- let new_authority_keypair = Keypair::new();
- let authority_instruction = loader_v4_instruction::transfer_authority(
- &program_id,
- &authority_keypair.pubkey(),
- &new_authority_keypair.pubkey(),
- );
- let message = Message::new(&[authority_instruction], Some(&mint_keypair.pubkey()));
- bank_client
- .send_and_confirm_message(
- &[&mint_keypair, &authority_keypair, &new_authority_keypair],
- message,
- )
- .unwrap();
- // Upgrade program
- let (source_program_keypair, mut deployment_instructions) =
- instructions_to_load_program_of_loader_v4(
- &bank_client,
- &mint_keypair,
- &new_authority_keypair,
- "solana_sbf_rust_upgraded",
- None,
- Some(&program_id),
- );
- deployment_instructions.insert(
- deployment_instructions.len() - 3,
- loader_v4_instruction::retract(&program_id, &new_authority_keypair.pubkey()),
- );
- let signers: &[&[&Keypair]] = &[
- &[&mint_keypair, &source_program_keypair],
- &[&mint_keypair, &new_authority_keypair],
- ];
- let signers = std::iter::once(signers[0]).chain(std::iter::repeat(signers[1]));
- for (instruction, signers) in deployment_instructions.into_iter().zip(signers) {
- let message = Message::new(&[instruction], Some(&mint_keypair.pubkey()));
- bank_client
- .send_and_confirm_message(signers, message)
- .unwrap();
- }
- bank_client
- .advance_slot(1, &bank_forks, &Pubkey::default())
- .expect("Failed to advance the slot");
- // Call upgraded program
- instruction.data[0] += 1;
- let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction.clone());
- assert_eq!(
- result.unwrap_err().unwrap(),
- TransactionError::InstructionError(0, InstructionError::Custom(43))
- );
- }
- #[test]
- #[cfg(feature = "sbf_rust")]
- fn test_program_sbf_upgrade_via_cpi() {
- agave_logger::setup();
- let GenesisConfigInfo {
- genesis_config,
- mint_keypair,
- ..
- } = create_genesis_config(50);
- let (bank, bank_forks) = Bank::new_with_bank_forks_for_tests(&genesis_config);
- let mut bank_client = BankClient::new_shared(bank);
- let authority_keypair = Keypair::new();
- let (_bank, invoke_and_return) = load_program_of_loader_v4(
- &mut bank_client,
- &bank_forks,
- &mint_keypair,
- &authority_keypair,
- "solana_sbf_rust_invoke_and_return",
- );
- // Deploy upgradeable program
- let authority_keypair = Keypair::new();
- let (_bank, program_id) = load_program_of_loader_v4(
- &mut bank_client,
- &bank_forks,
- &mint_keypair,
- &authority_keypair,
- "solana_sbf_rust_upgradeable",
- );
- // Call the upgradable program via CPI
- let mut instruction = Instruction::new_with_bytes(
- invoke_and_return,
- &[0],
- vec![
- AccountMeta::new_readonly(program_id, false),
- AccountMeta::new_readonly(clock::id(), false),
- ],
- );
- instruction.data[0] += 1;
- let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction.clone());
- assert_eq!(
- result.unwrap_err().unwrap(),
- TransactionError::InstructionError(0, InstructionError::Custom(42))
- );
- // Set authority via CPI
- let new_authority_keypair = Keypair::new();
- let mut authority_instruction = loader_v4_instruction::transfer_authority(
- &program_id,
- &authority_keypair.pubkey(),
- &new_authority_keypair.pubkey(),
- );
- authority_instruction.program_id = invoke_and_return;
- authority_instruction
- .accounts
- .insert(0, AccountMeta::new(loader_v4::id(), false));
- let message = Message::new(&[authority_instruction], Some(&mint_keypair.pubkey()));
- bank_client
- .send_and_confirm_message(
- &[&mint_keypair, &authority_keypair, &new_authority_keypair],
- message,
- )
- .unwrap();
- // Upgrade program via CPI
- let (source_program_keypair, mut deployment_instructions) =
- instructions_to_load_program_of_loader_v4(
- &bank_client,
- &mint_keypair,
- &new_authority_keypair,
- "solana_sbf_rust_upgraded",
- None,
- Some(&program_id),
- );
- deployment_instructions.insert(
- deployment_instructions.len() - 3,
- loader_v4_instruction::retract(&program_id, &new_authority_keypair.pubkey()),
- );
- let mut upgrade_instruction = deployment_instructions.pop().unwrap();
- let signers: &[&[&Keypair]] = &[
- &[&mint_keypair, &source_program_keypair],
- &[&mint_keypair, &new_authority_keypair],
- ];
- let signers = std::iter::once(signers[0]).chain(std::iter::repeat(signers[1]));
- for (instruction, signers) in deployment_instructions.into_iter().zip(signers) {
- let message = Message::new(&[instruction], Some(&mint_keypair.pubkey()));
- bank_client
- .send_and_confirm_message(signers, message)
- .unwrap();
- }
- upgrade_instruction.program_id = invoke_and_return;
- upgrade_instruction
- .accounts
- .insert(0, AccountMeta::new(loader_v4::id(), false));
- let message = Message::new(&[upgrade_instruction], Some(&mint_keypair.pubkey()));
- bank_client
- .send_and_confirm_message(&[&mint_keypair, &new_authority_keypair], message)
- .unwrap();
- bank_client
- .advance_slot(1, &bank_forks, &Pubkey::default())
- .expect("Failed to advance the slot");
- // Call the upgraded program via CPI
- instruction.data[0] += 1;
- let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction.clone());
- assert_eq!(
- result.unwrap_err().unwrap(),
- TransactionError::InstructionError(0, InstructionError::Custom(43))
- );
- }
- #[test]
- #[cfg(feature = "sbf_rust")]
- fn test_program_sbf_ro_account_modify() {
- agave_logger::setup();
- let GenesisConfigInfo {
- genesis_config,
- mint_keypair,
- ..
- } = create_genesis_config(50);
- let (bank, bank_forks) = Bank::new_with_bank_forks_for_tests(&genesis_config);
- let mut bank_client = BankClient::new_shared(bank.clone());
- let authority_keypair = Keypair::new();
- let (bank, program_id) = load_program_of_loader_v4(
- &mut bank_client,
- &bank_forks,
- &mint_keypair,
- &authority_keypair,
- "solana_sbf_rust_ro_account_modify",
- );
- let argument_keypair = Keypair::new();
- let account = AccountSharedData::new(42, 100, &program_id);
- bank.store_account(&argument_keypair.pubkey(), &account);
- let from_keypair = Keypair::new();
- let account = AccountSharedData::new(84, 0, &system_program::id());
- bank.store_account(&from_keypair.pubkey(), &account);
- let mint_pubkey = mint_keypair.pubkey();
- let account_metas = vec![
- AccountMeta::new_readonly(argument_keypair.pubkey(), false),
- AccountMeta::new_readonly(program_id, false),
- ];
- let instruction = Instruction::new_with_bytes(program_id, &[0], account_metas.clone());
- let message = Message::new(&[instruction], Some(&mint_pubkey));
- let result = bank_client.send_and_confirm_message(&[&mint_keypair], message);
- assert_eq!(
- result.unwrap_err().unwrap(),
- TransactionError::InstructionError(0, InstructionError::ReadonlyDataModified)
- );
- let instruction = Instruction::new_with_bytes(program_id, &[1], account_metas.clone());
- let message = Message::new(&[instruction], Some(&mint_pubkey));
- let result = bank_client.send_and_confirm_message(&[&mint_keypair], message);
- assert_eq!(
- result.unwrap_err().unwrap(),
- TransactionError::InstructionError(0, InstructionError::ReadonlyDataModified)
- );
- let instruction = Instruction::new_with_bytes(program_id, &[2], account_metas.clone());
- let message = Message::new(&[instruction], Some(&mint_pubkey));
- let result = bank_client.send_and_confirm_message(&[&mint_keypair], message);
- assert_eq!(
- result.unwrap_err().unwrap(),
- TransactionError::InstructionError(0, InstructionError::ReadonlyDataModified)
- );
- }
- #[test]
- #[cfg(feature = "sbf_rust")]
- fn test_program_sbf_realloc() {
- agave_logger::setup();
- const START_BALANCE: u64 = 100_000_000_000;
- let GenesisConfigInfo {
- genesis_config,
- mint_keypair,
- ..
- } = create_genesis_config(1_000_000_000_000);
- let mint_pubkey = mint_keypair.pubkey();
- let signer = &[&mint_keypair];
- for stricter_abi_and_runtime_constraints in [false, true] {
- let mut bank = Bank::new_for_tests(&genesis_config);
- let feature_set = Arc::make_mut(&mut bank.feature_set);
- // by default test banks have all features enabled, so we only need to
- // disable when needed
- if !stricter_abi_and_runtime_constraints {
- feature_set.deactivate(&feature_set::stricter_abi_and_runtime_constraints::id());
- feature_set.deactivate(&feature_set::account_data_direct_mapping::id());
- }
- let (bank, bank_forks) = bank.wrap_with_bank_forks_for_tests();
- let mut bank_client = BankClient::new_shared(bank.clone());
- let authority_keypair = Keypair::new();
- let (bank, program_id) = load_program_of_loader_v4(
- &mut bank_client,
- &bank_forks,
- &mint_keypair,
- &authority_keypair,
- "solana_sbf_rust_realloc",
- );
- let mut bump = 0;
- let keypair = Keypair::new();
- let pubkey = keypair.pubkey();
- let account = AccountSharedData::new(START_BALANCE, 5, &program_id);
- bank.store_account(&pubkey, &account);
- // Realloc RO account
- let mut instruction = realloc(&program_id, &pubkey, 0, &mut bump);
- instruction.accounts[0].is_writable = false;
- assert_eq!(
- bank_client
- .send_and_confirm_message(
- signer,
- Message::new(
- &[
- instruction,
- ComputeBudgetInstruction::set_loaded_accounts_data_size_limit(
- LOADED_ACCOUNTS_DATA_SIZE_LIMIT_FOR_TEST
- ),
- ],
- Some(&mint_pubkey),
- ),
- )
- .unwrap_err()
- .unwrap(),
- TransactionError::InstructionError(0, InstructionError::ReadonlyDataModified)
- );
- // Realloc account to overflow
- assert_eq!(
- bank_client
- .send_and_confirm_message(
- signer,
- Message::new(
- &[
- realloc(&program_id, &pubkey, usize::MAX, &mut bump),
- ComputeBudgetInstruction::set_loaded_accounts_data_size_limit(
- LOADED_ACCOUNTS_DATA_SIZE_LIMIT_FOR_TEST
- ),
- ],
- Some(&mint_pubkey),
- ),
- )
- .unwrap_err()
- .unwrap(),
- TransactionError::InstructionError(0, InstructionError::InvalidRealloc)
- );
- // Realloc account to 0
- bank_client
- .send_and_confirm_message(
- signer,
- Message::new(
- &[
- realloc(&program_id, &pubkey, 0, &mut bump),
- ComputeBudgetInstruction::set_loaded_accounts_data_size_limit(
- LOADED_ACCOUNTS_DATA_SIZE_LIMIT_FOR_TEST,
- ),
- ],
- Some(&mint_pubkey),
- ),
- )
- .unwrap();
- let data = bank_client.get_account_data(&pubkey).unwrap().unwrap();
- assert_eq!(0, data.len());
- // Realloc account to max then undo
- bank_client
- .send_and_confirm_message(
- signer,
- Message::new(
- &[
- realloc_extend_and_undo(
- &program_id,
- &pubkey,
- MAX_PERMITTED_DATA_INCREASE,
- &mut bump,
- ),
- ComputeBudgetInstruction::set_loaded_accounts_data_size_limit(
- LOADED_ACCOUNTS_DATA_SIZE_LIMIT_FOR_TEST,
- ),
- ],
- Some(&mint_pubkey),
- ),
- )
- .unwrap();
- let data = bank_client.get_account_data(&pubkey).unwrap().unwrap();
- assert_eq!(0, data.len());
- // Realloc account to max + 1 then undo
- assert_eq!(
- bank_client
- .send_and_confirm_message(
- signer,
- Message::new(
- &[
- realloc_extend_and_undo(
- &program_id,
- &pubkey,
- MAX_PERMITTED_DATA_INCREASE + 1,
- &mut bump,
- ),
- ComputeBudgetInstruction::set_loaded_accounts_data_size_limit(
- LOADED_ACCOUNTS_DATA_SIZE_LIMIT_FOR_TEST
- ),
- ],
- Some(&mint_pubkey),
- ),
- )
- .unwrap_err()
- .unwrap(),
- TransactionError::InstructionError(0, InstructionError::InvalidRealloc)
- );
- // Realloc to max + 1
- assert_eq!(
- bank_client
- .send_and_confirm_message(
- signer,
- Message::new(
- &[
- realloc(
- &program_id,
- &pubkey,
- MAX_PERMITTED_DATA_INCREASE + 1,
- &mut bump
- ),
- ComputeBudgetInstruction::set_loaded_accounts_data_size_limit(
- LOADED_ACCOUNTS_DATA_SIZE_LIMIT_FOR_TEST
- ),
- ],
- Some(&mint_pubkey),
- ),
- )
- .unwrap_err()
- .unwrap(),
- TransactionError::InstructionError(0, InstructionError::InvalidRealloc)
- );
- // Realloc to max length in max increase increments
- for i in 0..MAX_PERMITTED_DATA_LENGTH as usize / MAX_PERMITTED_DATA_INCREASE {
- let mut bump = i as u64;
- bank_client
- .send_and_confirm_message(
- signer,
- Message::new(
- &[
- realloc_extend_and_fill(
- &program_id,
- &pubkey,
- MAX_PERMITTED_DATA_INCREASE,
- 1,
- &mut bump,
- ),
- ComputeBudgetInstruction::set_loaded_accounts_data_size_limit(
- LOADED_ACCOUNTS_DATA_SIZE_LIMIT_FOR_TEST,
- ),
- ],
- Some(&mint_pubkey),
- ),
- )
- .unwrap();
- let data = bank_client.get_account_data(&pubkey).unwrap().unwrap();
- assert_eq!((i + 1) * MAX_PERMITTED_DATA_INCREASE, data.len());
- }
- for i in 0..data.len() {
- assert_eq!(data[i], 1);
- }
- // and one more time should fail
- assert_eq!(
- bank_client
- .send_and_confirm_message(
- signer,
- Message::new(
- &[
- realloc_extend(
- &program_id,
- &pubkey,
- MAX_PERMITTED_DATA_INCREASE,
- &mut bump
- ),
- ComputeBudgetInstruction::set_loaded_accounts_data_size_limit(
- LOADED_ACCOUNTS_DATA_SIZE_LIMIT_FOR_TEST
- ),
- ],
- Some(&mint_pubkey),
- )
- )
- .unwrap_err()
- .unwrap(),
- TransactionError::InstructionError(0, InstructionError::InvalidRealloc)
- );
- // Realloc to 6 bytes
- bank_client
- .send_and_confirm_message(
- signer,
- Message::new(
- &[
- realloc(&program_id, &pubkey, 6, &mut bump),
- ComputeBudgetInstruction::set_loaded_accounts_data_size_limit(
- LOADED_ACCOUNTS_DATA_SIZE_LIMIT_FOR_TEST,
- ),
- ],
- Some(&mint_pubkey),
- ),
- )
- .unwrap();
- let data = bank_client.get_account_data(&pubkey).unwrap().unwrap();
- assert_eq!(6, data.len());
- // Extend by 2 bytes and write a u64. This ensures that we can do writes that span the original
- // account length (6 bytes) and the realloc data (2 bytes).
- bank_client
- .send_and_confirm_message(
- signer,
- Message::new(
- &[
- extend_and_write_u64(&program_id, &pubkey, 0x1122334455667788),
- ComputeBudgetInstruction::set_loaded_accounts_data_size_limit(
- LOADED_ACCOUNTS_DATA_SIZE_LIMIT_FOR_TEST,
- ),
- ],
- Some(&mint_pubkey),
- ),
- )
- .unwrap();
- let data = bank_client.get_account_data(&pubkey).unwrap().unwrap();
- assert_eq!(8, data.len());
- assert_eq!(0x1122334455667788, unsafe { *data.as_ptr().cast::<u64>() });
- // Realloc to 0
- bank_client
- .send_and_confirm_message(
- signer,
- Message::new(
- &[
- realloc(&program_id, &pubkey, 0, &mut bump),
- ComputeBudgetInstruction::set_loaded_accounts_data_size_limit(
- LOADED_ACCOUNTS_DATA_SIZE_LIMIT_FOR_TEST,
- ),
- ],
- Some(&mint_pubkey),
- ),
- )
- .unwrap();
- let data = bank_client.get_account_data(&pubkey).unwrap().unwrap();
- assert_eq!(0, data.len());
- // Realloc and assign
- bank_client
- .send_and_confirm_message(
- signer,
- Message::new(
- &[
- Instruction::new_with_bytes(
- program_id,
- &[REALLOC_AND_ASSIGN],
- vec![AccountMeta::new(pubkey, false)],
- ),
- ComputeBudgetInstruction::set_loaded_accounts_data_size_limit(
- LOADED_ACCOUNTS_DATA_SIZE_LIMIT_FOR_TEST,
- ),
- ],
- Some(&mint_pubkey),
- ),
- )
- .unwrap();
- let account = bank.get_account(&pubkey).unwrap();
- assert_eq!(&solana_system_interface::program::id(), account.owner());
- let data = bank_client.get_account_data(&pubkey).unwrap().unwrap();
- assert_eq!(MAX_PERMITTED_DATA_INCREASE, data.len());
- // Realloc to 0 with wrong owner
- assert_eq!(
- bank_client
- .send_and_confirm_message(
- signer,
- Message::new(
- &[
- realloc(&program_id, &pubkey, 0, &mut bump),
- ComputeBudgetInstruction::set_loaded_accounts_data_size_limit(
- LOADED_ACCOUNTS_DATA_SIZE_LIMIT_FOR_TEST
- ),
- ],
- Some(&mint_pubkey),
- ),
- )
- .unwrap_err()
- .unwrap(),
- TransactionError::InstructionError(0, InstructionError::AccountDataSizeChanged)
- );
- // realloc and assign to self via cpi
- assert_eq!(
- bank_client
- .send_and_confirm_message(
- &[&mint_keypair, &keypair],
- Message::new(
- &[
- Instruction::new_with_bytes(
- program_id,
- &[REALLOC_AND_ASSIGN_TO_SELF_VIA_SYSTEM_PROGRAM],
- vec![
- AccountMeta::new(pubkey, true),
- AccountMeta::new(solana_system_interface::program::id(), false),
- ],
- ),
- ComputeBudgetInstruction::set_loaded_accounts_data_size_limit(
- LOADED_ACCOUNTS_DATA_SIZE_LIMIT_FOR_TEST
- ),
- ],
- Some(&mint_pubkey),
- )
- )
- .unwrap_err()
- .unwrap(),
- TransactionError::InstructionError(0, InstructionError::AccountDataSizeChanged)
- );
- // Assign to self and realloc via cpi
- bank_client
- .send_and_confirm_message(
- &[&mint_keypair, &keypair],
- Message::new(
- &[
- Instruction::new_with_bytes(
- program_id,
- &[ASSIGN_TO_SELF_VIA_SYSTEM_PROGRAM_AND_REALLOC],
- vec![
- AccountMeta::new(pubkey, true),
- AccountMeta::new(solana_system_interface::program::id(), false),
- ],
- ),
- ComputeBudgetInstruction::set_loaded_accounts_data_size_limit(
- LOADED_ACCOUNTS_DATA_SIZE_LIMIT_FOR_TEST,
- ),
- ],
- Some(&mint_pubkey),
- ),
- )
- .unwrap();
- let account = bank.get_account(&pubkey).unwrap();
- assert_eq!(&program_id, account.owner());
- let data = bank_client.get_account_data(&pubkey).unwrap().unwrap();
- assert_eq!(2 * MAX_PERMITTED_DATA_INCREASE, data.len());
- // Realloc to 0
- bank_client
- .send_and_confirm_message(
- signer,
- Message::new(
- &[
- realloc(&program_id, &pubkey, 0, &mut bump),
- ComputeBudgetInstruction::set_loaded_accounts_data_size_limit(
- LOADED_ACCOUNTS_DATA_SIZE_LIMIT_FOR_TEST,
- ),
- ],
- Some(&mint_pubkey),
- ),
- )
- .unwrap();
- let data = bank_client.get_account_data(&pubkey).unwrap().unwrap();
- assert_eq!(0, data.len());
- // zero-init
- bank_client
- .send_and_confirm_message(
- &[&mint_keypair, &keypair],
- Message::new(
- &[
- Instruction::new_with_bytes(
- program_id,
- &[ZERO_INIT],
- vec![AccountMeta::new(pubkey, true)],
- ),
- ComputeBudgetInstruction::set_loaded_accounts_data_size_limit(
- LOADED_ACCOUNTS_DATA_SIZE_LIMIT_FOR_TEST,
- ),
- ],
- Some(&mint_pubkey),
- ),
- )
- .unwrap();
- }
- }
- #[test]
- #[cfg(feature = "sbf_rust")]
- fn test_program_sbf_realloc_invoke() {
- agave_logger::setup();
- const START_BALANCE: u64 = 100_000_000_000;
- let GenesisConfigInfo {
- mut genesis_config,
- mint_keypair,
- ..
- } = create_genesis_config(1_000_000_000_000);
- genesis_config.rent = Rent::default();
- let mint_pubkey = mint_keypair.pubkey();
- let signer = &[&mint_keypair];
- let (bank, bank_forks) = Bank::new_with_bank_forks_for_tests(&genesis_config);
- let mut bank_client = BankClient::new_shared(bank.clone());
- let authority_keypair = Keypair::new();
- let (_bank, realloc_program_id) = load_program_of_loader_v4(
- &mut bank_client,
- &bank_forks,
- &mint_keypair,
- &authority_keypair,
- "solana_sbf_rust_realloc",
- );
- let (bank, realloc_invoke_program_id) = load_program_of_loader_v4(
- &mut bank_client,
- &bank_forks,
- &mint_keypair,
- &authority_keypair,
- "solana_sbf_rust_realloc_invoke",
- );
- let mut bump = 0;
- let keypair = Keypair::new();
- let pubkey = keypair.pubkey().clone();
- let account = AccountSharedData::new(START_BALANCE, 5, &realloc_program_id);
- bank.store_account(&pubkey, &account);
- let invoke_keypair = Keypair::new();
- let invoke_pubkey = invoke_keypair.pubkey().clone();
- // Realloc RO account
- assert_eq!(
- bank_client
- .send_and_confirm_message(
- signer,
- Message::new(
- &[
- Instruction::new_with_bytes(
- realloc_invoke_program_id,
- &[INVOKE_REALLOC_ZERO_RO],
- vec![
- AccountMeta::new_readonly(pubkey, false),
- AccountMeta::new_readonly(realloc_program_id, false),
- ],
- ),
- ComputeBudgetInstruction::set_loaded_accounts_data_size_limit(
- LOADED_ACCOUNTS_DATA_SIZE_LIMIT_FOR_TEST
- ),
- ],
- Some(&mint_pubkey),
- )
- )
- .unwrap_err()
- .unwrap(),
- TransactionError::InstructionError(0, InstructionError::ReadonlyDataModified)
- );
- let account = bank.get_account(&pubkey).unwrap();
- assert_eq!(account.lamports(), START_BALANCE);
- // Realloc account to 0
- bank_client
- .send_and_confirm_message(
- signer,
- Message::new(
- &[
- realloc(&realloc_program_id, &pubkey, 0, &mut bump),
- ComputeBudgetInstruction::set_loaded_accounts_data_size_limit(
- LOADED_ACCOUNTS_DATA_SIZE_LIMIT_FOR_TEST,
- ),
- ],
- Some(&mint_pubkey),
- ),
- )
- .unwrap();
- let account = bank.get_account(&pubkey).unwrap();
- assert_eq!(account.lamports(), START_BALANCE);
- let data = bank_client.get_account_data(&pubkey).unwrap().unwrap();
- assert_eq!(0, data.len());
- // Realloc to max + 1
- assert_eq!(
- bank_client
- .send_and_confirm_message(
- signer,
- Message::new(
- &[
- Instruction::new_with_bytes(
- realloc_invoke_program_id,
- &[INVOKE_REALLOC_MAX_PLUS_ONE],
- vec![
- AccountMeta::new(pubkey, false),
- AccountMeta::new_readonly(realloc_program_id, false),
- ],
- ),
- ComputeBudgetInstruction::set_loaded_accounts_data_size_limit(
- LOADED_ACCOUNTS_DATA_SIZE_LIMIT_FOR_TEST
- ),
- ],
- Some(&mint_pubkey),
- )
- )
- .unwrap_err()
- .unwrap(),
- TransactionError::InstructionError(0, InstructionError::InvalidRealloc)
- );
- // Realloc to max twice
- assert_eq!(
- bank_client
- .send_and_confirm_message(
- signer,
- Message::new(
- &[
- Instruction::new_with_bytes(
- realloc_invoke_program_id,
- &[INVOKE_REALLOC_MAX_TWICE],
- vec![
- AccountMeta::new(pubkey, false),
- AccountMeta::new_readonly(realloc_program_id, false),
- ],
- ),
- ComputeBudgetInstruction::set_loaded_accounts_data_size_limit(
- LOADED_ACCOUNTS_DATA_SIZE_LIMIT_FOR_TEST
- ),
- ],
- Some(&mint_pubkey),
- )
- )
- .unwrap_err()
- .unwrap(),
- TransactionError::InstructionError(0, InstructionError::InvalidRealloc)
- );
- // Realloc account to 0
- bank_client
- .send_and_confirm_message(
- signer,
- Message::new(
- &[
- realloc(&realloc_program_id, &pubkey, 0, &mut bump),
- ComputeBudgetInstruction::set_loaded_accounts_data_size_limit(
- LOADED_ACCOUNTS_DATA_SIZE_LIMIT_FOR_TEST,
- ),
- ],
- Some(&mint_pubkey),
- ),
- )
- .unwrap();
- let account = bank.get_account(&pubkey).unwrap();
- assert_eq!(account.lamports(), START_BALANCE);
- let data = bank_client.get_account_data(&pubkey).unwrap().unwrap();
- assert_eq!(0, data.len());
- // Realloc and assign
- bank_client
- .send_and_confirm_message(
- signer,
- Message::new(
- &[
- Instruction::new_with_bytes(
- realloc_invoke_program_id,
- &[INVOKE_REALLOC_AND_ASSIGN],
- vec![
- AccountMeta::new(pubkey, false),
- AccountMeta::new_readonly(realloc_program_id, false),
- ],
- ),
- ComputeBudgetInstruction::set_loaded_accounts_data_size_limit(
- LOADED_ACCOUNTS_DATA_SIZE_LIMIT_FOR_TEST,
- ),
- ],
- Some(&mint_pubkey),
- ),
- )
- .unwrap();
- let account = bank.get_account(&pubkey).unwrap();
- assert_eq!(&solana_system_interface::program::id(), account.owner());
- let data = bank_client.get_account_data(&pubkey).unwrap().unwrap();
- assert_eq!(MAX_PERMITTED_DATA_INCREASE, data.len());
- // Realloc to 0 with wrong owner
- assert_eq!(
- bank_client
- .send_and_confirm_message(
- signer,
- Message::new(
- &[
- realloc(&realloc_program_id, &pubkey, 0, &mut bump),
- ComputeBudgetInstruction::set_loaded_accounts_data_size_limit(
- LOADED_ACCOUNTS_DATA_SIZE_LIMIT_FOR_TEST
- ),
- ],
- Some(&mint_pubkey),
- )
- )
- .unwrap_err()
- .unwrap(),
- TransactionError::InstructionError(0, InstructionError::AccountDataSizeChanged)
- );
- // realloc and assign to self via system program
- assert_eq!(
- bank_client
- .send_and_confirm_message(
- &[&mint_keypair, &keypair],
- Message::new(
- &[
- Instruction::new_with_bytes(
- realloc_invoke_program_id,
- &[INVOKE_REALLOC_AND_ASSIGN_TO_SELF_VIA_SYSTEM_PROGRAM],
- vec![
- AccountMeta::new(pubkey, true),
- AccountMeta::new_readonly(realloc_program_id, false),
- AccountMeta::new_readonly(
- solana_system_interface::program::id(),
- false
- ),
- ],
- ),
- ComputeBudgetInstruction::set_loaded_accounts_data_size_limit(
- LOADED_ACCOUNTS_DATA_SIZE_LIMIT_FOR_TEST
- ),
- ],
- Some(&mint_pubkey),
- )
- )
- .unwrap_err()
- .unwrap(),
- TransactionError::InstructionError(0, InstructionError::AccountDataSizeChanged)
- );
- // Assign to self and realloc via system program
- bank_client
- .send_and_confirm_message(
- &[&mint_keypair, &keypair],
- Message::new(
- &[
- Instruction::new_with_bytes(
- realloc_invoke_program_id,
- &[INVOKE_ASSIGN_TO_SELF_VIA_SYSTEM_PROGRAM_AND_REALLOC],
- vec![
- AccountMeta::new(pubkey, true),
- AccountMeta::new_readonly(realloc_program_id, false),
- AccountMeta::new_readonly(
- solana_system_interface::program::id(),
- false,
- ),
- ],
- ),
- ComputeBudgetInstruction::set_loaded_accounts_data_size_limit(
- LOADED_ACCOUNTS_DATA_SIZE_LIMIT_FOR_TEST,
- ),
- ],
- Some(&mint_pubkey),
- ),
- )
- .unwrap();
- let account = bank.get_account(&pubkey).unwrap();
- assert_eq!(&realloc_program_id, account.owner());
- let data = bank_client.get_account_data(&pubkey).unwrap().unwrap();
- assert_eq!(2 * MAX_PERMITTED_DATA_INCREASE, data.len());
- // Realloc to 0
- bank_client
- .send_and_confirm_message(
- signer,
- Message::new(
- &[
- realloc(&realloc_program_id, &pubkey, 0, &mut bump),
- ComputeBudgetInstruction::set_loaded_accounts_data_size_limit(
- LOADED_ACCOUNTS_DATA_SIZE_LIMIT_FOR_TEST,
- ),
- ],
- Some(&mint_pubkey),
- ),
- )
- .unwrap();
- let data = bank_client.get_account_data(&pubkey).unwrap().unwrap();
- assert_eq!(0, data.len());
- // Realloc to 100 and check via CPI
- let invoke_account = AccountSharedData::new(START_BALANCE, 5, &realloc_invoke_program_id);
- bank.store_account(&invoke_pubkey, &invoke_account);
- bank_client
- .send_and_confirm_message(
- signer,
- Message::new(
- &[
- Instruction::new_with_bytes(
- realloc_invoke_program_id,
- &[INVOKE_REALLOC_INVOKE_CHECK],
- vec![
- AccountMeta::new(invoke_pubkey, false),
- AccountMeta::new_readonly(realloc_program_id, false),
- ],
- ),
- ComputeBudgetInstruction::set_loaded_accounts_data_size_limit(
- LOADED_ACCOUNTS_DATA_SIZE_LIMIT_FOR_TEST,
- ),
- ],
- Some(&mint_pubkey),
- ),
- )
- .unwrap();
- let data = bank_client
- .get_account_data(&invoke_pubkey)
- .unwrap()
- .unwrap();
- assert_eq!(100, data.len());
- for i in 0..5 {
- assert_eq!(data[i], 0);
- }
- for i in 5..data.len() {
- assert_eq!(data[i], 2);
- }
- // Create account, realloc, check
- let new_keypair = Keypair::new();
- let new_pubkey = new_keypair.pubkey().clone();
- let mut instruction_data = vec![];
- instruction_data.extend_from_slice(&[INVOKE_CREATE_ACCOUNT_REALLOC_CHECK, 1]);
- instruction_data.extend_from_slice(&100_usize.to_le_bytes());
- bank_client
- .send_and_confirm_message(
- &[&mint_keypair, &new_keypair],
- Message::new(
- &[
- Instruction::new_with_bytes(
- realloc_invoke_program_id,
- &instruction_data,
- vec![
- AccountMeta::new(mint_pubkey, true),
- AccountMeta::new(new_pubkey, true),
- AccountMeta::new(solana_system_interface::program::id(), false),
- AccountMeta::new_readonly(realloc_invoke_program_id, false),
- ],
- ),
- ComputeBudgetInstruction::set_loaded_accounts_data_size_limit(
- LOADED_ACCOUNTS_DATA_SIZE_LIMIT_FOR_TEST,
- ),
- ],
- Some(&mint_pubkey),
- ),
- )
- .unwrap();
- let data = bank_client.get_account_data(&new_pubkey).unwrap().unwrap();
- assert_eq!(200, data.len());
- let account = bank.get_account(&new_pubkey).unwrap();
- assert_eq!(&realloc_invoke_program_id, account.owner());
- // Invoke, dealloc, and assign
- let pre_len = 100;
- let new_len = pre_len * 2;
- let mut invoke_account = AccountSharedData::new(START_BALANCE, pre_len, &realloc_program_id);
- invoke_account.set_data_from_slice(&vec![1; pre_len]);
- bank.store_account(&invoke_pubkey, &invoke_account);
- let mut instruction_data = vec![];
- instruction_data.extend_from_slice(&[INVOKE_DEALLOC_AND_ASSIGN, 1]);
- instruction_data.extend_from_slice(&pre_len.to_le_bytes());
- bank_client
- .send_and_confirm_message(
- signer,
- Message::new(
- &[
- Instruction::new_with_bytes(
- realloc_invoke_program_id,
- &instruction_data,
- vec![
- AccountMeta::new(invoke_pubkey, false),
- AccountMeta::new_readonly(realloc_invoke_program_id, false),
- AccountMeta::new_readonly(realloc_program_id, false),
- ],
- ),
- ComputeBudgetInstruction::set_loaded_accounts_data_size_limit(
- LOADED_ACCOUNTS_DATA_SIZE_LIMIT_FOR_TEST,
- ),
- ],
- Some(&mint_pubkey),
- ),
- )
- .unwrap();
- let data = bank_client
- .get_account_data(&invoke_pubkey)
- .unwrap()
- .unwrap();
- assert_eq!(new_len, data.len());
- for i in 0..new_len {
- assert_eq!(data[i], 0);
- }
- // Realloc to max invoke max
- let invoke_account = AccountSharedData::new(42, 0, &realloc_invoke_program_id);
- bank.store_account(&invoke_pubkey, &invoke_account);
- assert_eq!(
- bank_client
- .send_and_confirm_message(
- signer,
- Message::new(
- &[
- Instruction::new_with_bytes(
- realloc_invoke_program_id,
- &[INVOKE_REALLOC_MAX_INVOKE_MAX],
- vec![
- AccountMeta::new(invoke_pubkey, false),
- AccountMeta::new_readonly(realloc_program_id, false),
- ],
- ),
- ComputeBudgetInstruction::set_loaded_accounts_data_size_limit(
- LOADED_ACCOUNTS_DATA_SIZE_LIMIT_FOR_TEST
- ),
- ],
- Some(&mint_pubkey),
- )
- )
- .unwrap_err()
- .unwrap(),
- TransactionError::InstructionError(0, InstructionError::InvalidRealloc)
- );
- // CPI realloc extend then local realloc extend
- for (cpi_extend_bytes, local_extend_bytes, should_succeed) in [
- (0, 0, true),
- (MAX_PERMITTED_DATA_INCREASE, 0, true),
- (0, MAX_PERMITTED_DATA_INCREASE, true),
- (MAX_PERMITTED_DATA_INCREASE, 1, false),
- (1, MAX_PERMITTED_DATA_INCREASE, false),
- ] {
- let invoke_account = AccountSharedData::new(100_000_000, 0, &realloc_invoke_program_id);
- bank.store_account(&invoke_pubkey, &invoke_account);
- let mut instruction_data = vec![];
- instruction_data.extend_from_slice(&[INVOKE_REALLOC_TO_THEN_LOCAL_REALLOC_EXTEND, 1]);
- instruction_data.extend_from_slice(&cpi_extend_bytes.to_le_bytes());
- instruction_data.extend_from_slice(&local_extend_bytes.to_le_bytes());
- let result = bank_client.send_and_confirm_message(
- signer,
- Message::new(
- &[
- Instruction::new_with_bytes(
- realloc_invoke_program_id,
- &instruction_data,
- vec![
- AccountMeta::new(invoke_pubkey, false),
- AccountMeta::new_readonly(realloc_invoke_program_id, false),
- ],
- ),
- ComputeBudgetInstruction::set_loaded_accounts_data_size_limit(
- LOADED_ACCOUNTS_DATA_SIZE_LIMIT_FOR_TEST,
- ),
- ],
- Some(&mint_pubkey),
- ),
- );
- if should_succeed {
- assert!(
- result.is_ok(),
- "cpi: {cpi_extend_bytes} local: {local_extend_bytes}, err: {:?}",
- result.err()
- );
- } else {
- assert_eq!(
- result.unwrap_err().unwrap(),
- TransactionError::InstructionError(0, InstructionError::InvalidRealloc),
- "cpi: {cpi_extend_bytes} local: {local_extend_bytes}",
- );
- }
- }
- // Realloc invoke max twice
- let invoke_account = AccountSharedData::new(42, 0, &realloc_program_id);
- bank.store_account(&invoke_pubkey, &invoke_account);
- assert_eq!(
- bank_client
- .send_and_confirm_message(
- signer,
- Message::new(
- &[
- Instruction::new_with_bytes(
- realloc_invoke_program_id,
- &[INVOKE_INVOKE_MAX_TWICE],
- vec![
- AccountMeta::new(invoke_pubkey, false),
- AccountMeta::new_readonly(realloc_invoke_program_id, false),
- AccountMeta::new_readonly(realloc_program_id, false),
- ],
- ),
- ComputeBudgetInstruction::set_loaded_accounts_data_size_limit(
- LOADED_ACCOUNTS_DATA_SIZE_LIMIT_FOR_TEST
- ),
- ],
- Some(&mint_pubkey),
- )
- )
- .unwrap_err()
- .unwrap(),
- TransactionError::InstructionError(0, InstructionError::InvalidRealloc)
- );
- // Realloc to 0
- bank_client
- .send_and_confirm_message(
- signer,
- Message::new(
- &[realloc(&realloc_program_id, &pubkey, 0, &mut bump)],
- Some(&mint_pubkey),
- ),
- )
- .unwrap();
- let data = bank_client.get_account_data(&pubkey).unwrap().unwrap();
- assert_eq!(0, data.len());
- // Realloc to max length in max increase increments
- for i in 0..MAX_PERMITTED_DATA_LENGTH as usize / MAX_PERMITTED_DATA_INCREASE {
- bank_client
- .send_and_confirm_message(
- signer,
- Message::new(
- &[
- Instruction::new_with_bytes(
- realloc_invoke_program_id,
- &[INVOKE_REALLOC_EXTEND_MAX, 1, i as u8, (i / 255) as u8],
- vec![
- AccountMeta::new(pubkey, false),
- AccountMeta::new_readonly(realloc_program_id, false),
- ],
- ),
- ComputeBudgetInstruction::set_loaded_accounts_data_size_limit(
- LOADED_ACCOUNTS_DATA_SIZE_LIMIT_FOR_TEST,
- ),
- ],
- Some(&mint_pubkey),
- ),
- )
- .unwrap();
- let data = bank_client.get_account_data(&pubkey).unwrap().unwrap();
- assert_eq!((i + 1) * MAX_PERMITTED_DATA_INCREASE, data.len());
- }
- for i in 0..data.len() {
- assert_eq!(data[i], 1);
- }
- // and one more time should fail
- assert_eq!(
- bank_client
- .send_and_confirm_message(
- signer,
- Message::new(
- &[
- Instruction::new_with_bytes(
- realloc_invoke_program_id,
- &[INVOKE_REALLOC_EXTEND_MAX, 2, 1, 1],
- vec![
- AccountMeta::new(pubkey, false),
- AccountMeta::new_readonly(realloc_program_id, false),
- ],
- ),
- ComputeBudgetInstruction::set_loaded_accounts_data_size_limit(
- LOADED_ACCOUNTS_DATA_SIZE_LIMIT_FOR_TEST
- ),
- ],
- Some(&mint_pubkey),
- )
- )
- .unwrap_err()
- .unwrap(),
- TransactionError::InstructionError(0, InstructionError::InvalidRealloc)
- );
- // Realloc recursively and fill data
- let invoke_keypair = Keypair::new();
- let invoke_pubkey = invoke_keypair.pubkey().clone();
- let invoke_account = AccountSharedData::new(START_BALANCE, 0, &realloc_invoke_program_id);
- bank.store_account(&invoke_pubkey, &invoke_account);
- let mut instruction_data = vec![];
- instruction_data.extend_from_slice(&[INVOKE_REALLOC_RECURSIVE, 1]);
- instruction_data.extend_from_slice(&100_usize.to_le_bytes());
- bank_client
- .send_and_confirm_message(
- signer,
- Message::new(
- &[
- Instruction::new_with_bytes(
- realloc_invoke_program_id,
- &instruction_data,
- vec![
- AccountMeta::new(invoke_pubkey, false),
- AccountMeta::new_readonly(realloc_invoke_program_id, false),
- ],
- ),
- ComputeBudgetInstruction::set_loaded_accounts_data_size_limit(
- LOADED_ACCOUNTS_DATA_SIZE_LIMIT_FOR_TEST,
- ),
- ],
- Some(&mint_pubkey),
- ),
- )
- .unwrap();
- let data = bank_client
- .get_account_data(&invoke_pubkey)
- .unwrap()
- .unwrap();
- assert_eq!(200, data.len());
- for i in 0..100 {
- assert_eq!(data[i], 1);
- }
- for i in 100..200 {
- assert_eq!(data[i], 2);
- }
- }
- #[test]
- #[cfg(feature = "sbf_rust")]
- fn test_program_sbf_processed_inner_instruction() {
- agave_logger::setup();
- let GenesisConfigInfo {
- genesis_config,
- mint_keypair,
- ..
- } = create_genesis_config(50);
- let (bank, bank_forks) = Bank::new_with_bank_forks_for_tests(&genesis_config);
- let mut bank_client = BankClient::new_shared(bank.clone());
- let authority_keypair = Keypair::new();
- let (_bank, sibling_program_id) = load_program_of_loader_v4(
- &mut bank_client,
- &bank_forks,
- &mint_keypair,
- &authority_keypair,
- "solana_sbf_rust_sibling_instructions",
- );
- let (_bank, sibling_inner_program_id) = load_program_of_loader_v4(
- &mut bank_client,
- &bank_forks,
- &mint_keypair,
- &authority_keypair,
- "solana_sbf_rust_sibling_inner_instructions",
- );
- let (_bank, noop_program_id) = load_program_of_loader_v4(
- &mut bank_client,
- &bank_forks,
- &mint_keypair,
- &authority_keypair,
- "solana_sbf_rust_noop",
- );
- let (_bank, invoke_and_return_program_id) = load_program_of_loader_v4(
- &mut bank_client,
- &bank_forks,
- &mint_keypair,
- &authority_keypair,
- "solana_sbf_rust_invoke_and_return",
- );
- let instruction2 = Instruction::new_with_bytes(
- noop_program_id,
- &[43],
- vec![
- AccountMeta::new_readonly(noop_program_id, false),
- AccountMeta::new(mint_keypair.pubkey(), true),
- ],
- );
- let instruction1 = Instruction::new_with_bytes(
- noop_program_id,
- &[42],
- vec![
- AccountMeta::new(mint_keypair.pubkey(), true),
- AccountMeta::new_readonly(noop_program_id, false),
- ],
- );
- let instruction0 = Instruction::new_with_bytes(
- sibling_program_id,
- &[1, 2, 3, 0, 4, 5, 6],
- vec![
- AccountMeta::new(mint_keypair.pubkey(), true),
- AccountMeta::new_readonly(noop_program_id, false),
- AccountMeta::new_readonly(invoke_and_return_program_id, false),
- AccountMeta::new_readonly(sibling_inner_program_id, false),
- ],
- );
- let message = Message::new(
- &[instruction2, instruction1, instruction0],
- Some(&mint_keypair.pubkey()),
- );
- assert!(bank_client
- .send_and_confirm_message(&[&mint_keypair], message)
- .is_ok());
- }
- #[test]
- #[cfg(feature = "sbf_rust")]
- fn test_program_fees() {
- agave_logger::setup();
- let congestion_multiplier = 1;
- let GenesisConfigInfo {
- mut genesis_config,
- mint_keypair,
- ..
- } = create_genesis_config(500_000_000);
- genesis_config.fee_rate_governor = FeeRateGovernor::new(congestion_multiplier, 0);
- let mut bank = Bank::new_for_tests(&genesis_config);
- let fee_structure = FeeStructure {
- lamports_per_signature: 5000,
- lamports_per_write_lock: 0,
- compute_fee_bins: vec![
- FeeBin {
- limit: 200,
- fee: 500,
- },
- FeeBin {
- limit: 1400000,
- fee: 5000,
- },
- ],
- };
- bank.set_fee_structure(&fee_structure);
- let (bank, bank_forks) = bank.wrap_with_bank_forks_for_tests();
- let feature_set = bank.feature_set.clone();
- let mut bank_client = BankClient::new_shared(bank.clone());
- let authority_keypair = Keypair::new();
- let (_bank, program_id) = load_program_of_loader_v4(
- &mut bank_client,
- &bank_forks,
- &mint_keypair,
- &authority_keypair,
- "solana_sbf_rust_noop",
- );
- let pre_balance = bank_client.get_balance(&mint_keypair.pubkey()).unwrap();
- let message = Message::new(
- &[Instruction::new_with_bytes(program_id, &[], vec![])],
- Some(&mint_keypair.pubkey()),
- );
- let sanitized_message = SanitizedMessage::try_from_legacy_message(
- message.clone(),
- &ReservedAccountKeys::empty_key_set(),
- )
- .unwrap();
- let fee_budget_limits = FeeBudgetLimits::from(
- process_compute_budget_instructions(
- SVMStaticMessage::program_instructions_iter(&sanitized_message),
- &feature_set,
- )
- .unwrap_or_default(),
- );
- let expected_normal_fee = solana_fee::calculate_fee(
- &sanitized_message,
- congestion_multiplier == 0,
- fee_structure.lamports_per_signature,
- fee_budget_limits.prioritization_fee,
- bank.feature_set.as_ref().into(),
- );
- bank_client
- .send_and_confirm_message(&[&mint_keypair], message)
- .unwrap();
- let post_balance = bank_client.get_balance(&mint_keypair.pubkey()).unwrap();
- assert_eq!(pre_balance - post_balance, expected_normal_fee);
- let pre_balance = bank_client.get_balance(&mint_keypair.pubkey()).unwrap();
- let message = Message::new(
- &[
- ComputeBudgetInstruction::set_compute_unit_price(1),
- Instruction::new_with_bytes(program_id, &[], vec![]),
- ],
- Some(&mint_keypair.pubkey()),
- );
- let sanitized_message = SanitizedMessage::try_from_legacy_message(
- message.clone(),
- &ReservedAccountKeys::empty_key_set(),
- )
- .unwrap();
- let fee_budget_limits = FeeBudgetLimits::from(
- process_compute_budget_instructions(
- SVMStaticMessage::program_instructions_iter(&sanitized_message),
- &feature_set,
- )
- .unwrap_or_default(),
- );
- let expected_prioritized_fee = solana_fee::calculate_fee(
- &sanitized_message,
- congestion_multiplier == 0,
- fee_structure.lamports_per_signature,
- fee_budget_limits.prioritization_fee,
- bank.feature_set.as_ref().into(),
- );
- assert!(expected_normal_fee < expected_prioritized_fee);
- bank_client
- .send_and_confirm_message(&[&mint_keypair], message)
- .unwrap();
- let post_balance = bank_client.get_balance(&mint_keypair.pubkey()).unwrap();
- assert_eq!(pre_balance - post_balance, expected_prioritized_fee);
- }
- #[test]
- #[cfg(feature = "sbf_rust")]
- fn test_program_sbf_inner_instruction_alignment_checks() {
- agave_logger::setup();
- let GenesisConfigInfo {
- genesis_config,
- mint_keypair,
- ..
- } = create_genesis_config(50);
- let (bank, bank_forks) = Bank::new_with_bank_forks_for_tests(&genesis_config);
- let noop = create_program(&bank, &bpf_loader_deprecated::id(), "solana_sbf_rust_noop");
- let inner_instruction_alignment_check = create_program(
- &bank,
- &bpf_loader_deprecated::id(),
- "solana_sbf_rust_inner_instruction_alignment_check",
- );
- // invoke unaligned program, which will call aligned program twice,
- // unaligned should be allowed once invoke completes
- let mut bank_client = BankClient::new_shared(bank);
- bank_client
- .advance_slot(1, bank_forks.as_ref(), &Pubkey::default())
- .expect("Failed to advance the slot");
- let mut instruction = Instruction::new_with_bytes(
- inner_instruction_alignment_check,
- &[0],
- vec![
- AccountMeta::new_readonly(noop, false),
- AccountMeta::new_readonly(mint_keypair.pubkey(), false),
- ],
- );
- instruction.data[0] += 1;
- let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction.clone());
- assert!(result.is_ok(), "{result:?}");
- }
- #[test]
- #[cfg(feature = "sbf_rust")]
- fn test_cpi_account_ownership_writability() {
- agave_logger::setup();
- for stricter_abi_and_runtime_constraints in [false, true] {
- let GenesisConfigInfo {
- genesis_config,
- mint_keypair,
- ..
- } = create_genesis_config(100_123_456_789);
- let mut bank = Bank::new_for_tests(&genesis_config);
- let mut feature_set = FeatureSet::all_enabled();
- if !stricter_abi_and_runtime_constraints {
- feature_set.deactivate(&feature_set::stricter_abi_and_runtime_constraints::id());
- feature_set.deactivate(&feature_set::account_data_direct_mapping::id());
- }
- bank.feature_set = Arc::new(feature_set);
- let (bank, bank_forks) = bank.wrap_with_bank_forks_for_tests();
- let mut bank_client = BankClient::new_shared(bank);
- let authority_keypair = Keypair::new();
- let (_bank, invoke_program_id) = load_program_of_loader_v4(
- &mut bank_client,
- &bank_forks,
- &mint_keypair,
- &authority_keypair,
- "solana_sbf_rust_invoke",
- );
- let (_bank, invoked_program_id) = load_program_of_loader_v4(
- &mut bank_client,
- &bank_forks,
- &mint_keypair,
- &authority_keypair,
- "solana_sbf_rust_invoked",
- );
- let (bank, realloc_program_id) = load_program_of_loader_v4(
- &mut bank_client,
- &bank_forks,
- &mint_keypair,
- &authority_keypair,
- "solana_sbf_rust_realloc",
- );
- let account_keypair = Keypair::new();
- let mint_pubkey = mint_keypair.pubkey();
- let account_metas = vec![
- AccountMeta::new(mint_pubkey, true),
- AccountMeta::new(account_keypair.pubkey(), false),
- AccountMeta::new_readonly(invoked_program_id, false),
- AccountMeta::new_readonly(invoke_program_id, false),
- AccountMeta::new_readonly(realloc_program_id, false),
- ];
- for (account_size, byte_index) in [
- (0, 0), // first realloc byte
- (0, MAX_PERMITTED_DATA_INCREASE - 1), // last realloc byte
- (2, 0), // first data byte
- (2, 1), // last data byte
- (2, 3), // first realloc byte
- (2, 2 + MAX_PERMITTED_DATA_INCREASE - 1), // last realloc byte
- ] {
- for instruction_id in [
- TEST_FORBID_WRITE_AFTER_OWNERSHIP_CHANGE_IN_CALLEE,
- TEST_FORBID_WRITE_AFTER_OWNERSHIP_CHANGE_IN_CALLER,
- ] {
- bank.register_unique_recent_blockhash_for_test();
- let account = AccountSharedData::new(42, account_size, &invoke_program_id);
- bank.store_account(&account_keypair.pubkey(), &account);
- let mut instruction_data = vec![instruction_id];
- instruction_data.extend_from_slice(byte_index.to_le_bytes().as_ref());
- let instruction = Instruction::new_with_bytes(
- invoke_program_id,
- &instruction_data,
- account_metas.clone(),
- );
- let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
- if (byte_index as usize) < account_size || stricter_abi_and_runtime_constraints {
- assert_eq!(
- result.unwrap_err().unwrap(),
- TransactionError::InstructionError(
- 0,
- InstructionError::ExternalAccountDataModified,
- )
- );
- } else {
- // without stricter_abi_and_runtime_constraints, changes to the realloc padding
- // outside the account length are ignored
- assert!(result.is_ok(), "{result:?}");
- }
- }
- }
- // Test that the CPI code that updates `ref_to_len_in_vm` fails if we
- // make it write to an invalid location. This is the first variant which
- // correctly triggers ExternalAccountDataModified when stricter_abi_and_runtime_constraints is
- // disabled. When stricter_abi_and_runtime_constraints is enabled this tests fails early
- // because we move the account data pointer.
- // TEST_FORBID_LEN_UPDATE_AFTER_OWNERSHIP_CHANGE is able to make more
- // progress when stricter_abi_and_runtime_constraints is on.
- let account = AccountSharedData::new(42, 0, &invoke_program_id);
- bank.store_account(&account_keypair.pubkey(), &account);
- let instruction_data = vec![
- TEST_FORBID_LEN_UPDATE_AFTER_OWNERSHIP_CHANGE_MOVING_DATA_POINTER,
- 42,
- 42,
- 42,
- ];
- let instruction = Instruction::new_with_bytes(
- invoke_program_id,
- &instruction_data,
- account_metas.clone(),
- );
- let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
- assert_eq!(
- result.unwrap_err().unwrap(),
- if stricter_abi_and_runtime_constraints {
- // We move the data pointer, stricter_abi_and_runtime_constraints doesn't allow it
- // anymore so it errors out earlier. See
- // test_cpi_invalid_account_info_pointers.
- TransactionError::InstructionError(0, InstructionError::ProgramFailedToComplete)
- } else {
- // We managed to make CPI write into the account data, but the
- // usual checks still apply and we get an error.
- TransactionError::InstructionError(0, InstructionError::ExternalAccountDataModified)
- }
- );
- // We're going to try and make CPI write ref_to_len_in_vm into a 2nd
- // account, so we add an extra one here.
- let account2_keypair = Keypair::new();
- let mut account_metas = account_metas.clone();
- account_metas.push(AccountMeta::new(account2_keypair.pubkey(), false));
- for target_account in [1, account_metas.len() as u8 - 1] {
- // Similar to the test above where we try to make CPI write into account
- // data. This variant is for when stricter_abi_and_runtime_constraints is enabled.
- let account = AccountSharedData::new(42, 0, &invoke_program_id);
- bank.store_account(&account_keypair.pubkey(), &account);
- let account = AccountSharedData::new(42, 0, &invoke_program_id);
- bank.store_account(&account2_keypair.pubkey(), &account);
- let instruction_data = vec![
- TEST_FORBID_LEN_UPDATE_AFTER_OWNERSHIP_CHANGE,
- target_account,
- 42,
- 42,
- ];
- let instruction = Instruction::new_with_bytes(
- invoke_program_id,
- &instruction_data,
- account_metas.clone(),
- );
- let message = Message::new(&[instruction], Some(&mint_pubkey));
- let tx = Transaction::new(&[&mint_keypair], message.clone(), bank.last_blockhash());
- let (result, _, logs, _) = process_transaction_and_record_inner(&bank, tx);
- if stricter_abi_and_runtime_constraints {
- assert_eq!(
- result.unwrap_err(),
- TransactionError::InstructionError(
- 0,
- InstructionError::ProgramFailedToComplete
- )
- );
- // We haven't moved the data pointer, but ref_to_len_vm _is_ in
- // the account data vm range and that's not allowed either.
- assert!(
- logs.iter().any(|log| log.contains("Invalid pointer")),
- "{logs:?}"
- );
- } else {
- // we expect this to succeed as after updating `ref_to_len_in_vm`,
- // CPI will sync the actual account data between the callee and the
- // caller, _always_ writing over the location pointed by
- // `ref_to_len_in_vm`. To verify this, we check that the account
- // data is in fact all zeroes like it is in the callee.
- result.unwrap();
- let account = bank.get_account(&account_keypair.pubkey()).unwrap();
- assert_eq!(account.data(), vec![0; 40]);
- }
- }
- // Test that the caller can write to an account which it received from the callee
- let account = AccountSharedData::new(42, 0, &invoked_program_id);
- bank.store_account(&account_keypair.pubkey(), &account);
- let instruction_data = vec![TEST_ALLOW_WRITE_AFTER_OWNERSHIP_CHANGE_TO_CALLER, 1, 42, 42];
- let instruction =
- Instruction::new_with_bytes(invoke_program_id, &instruction_data, account_metas);
- let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
- result.unwrap();
- }
- }
- #[test]
- #[cfg(feature = "sbf_rust")]
- fn test_cpi_account_data_updates() {
- agave_logger::setup();
- for (deprecated_callee, deprecated_caller, stricter_abi_and_runtime_constraints) in
- [false, true].into_iter().flat_map(move |z| {
- [false, true]
- .into_iter()
- .flat_map(move |y| [false, true].into_iter().map(move |x| (x, y, z)))
- })
- {
- let GenesisConfigInfo {
- genesis_config,
- mint_keypair,
- ..
- } = create_genesis_config(100_123_456_789);
- let mut bank = Bank::new_for_tests(&genesis_config);
- let mut feature_set = FeatureSet::all_enabled();
- if !stricter_abi_and_runtime_constraints {
- feature_set.deactivate(&feature_set::stricter_abi_and_runtime_constraints::id());
- feature_set.deactivate(&feature_set::account_data_direct_mapping::id());
- }
- bank.feature_set = Arc::new(feature_set);
- let (bank, bank_forks) = bank.wrap_with_bank_forks_for_tests();
- let mut bank_client = BankClient::new_shared(bank);
- let authority_keypair = Keypair::new();
- let (_bank, invoke_program_id) = load_program_of_loader_v4(
- &mut bank_client,
- &bank_forks,
- &mint_keypair,
- &authority_keypair,
- "solana_sbf_rust_invoke",
- );
- let (bank, realloc_program_id) = load_program_of_loader_v4(
- &mut bank_client,
- &bank_forks,
- &mint_keypair,
- &authority_keypair,
- "solana_sbf_rust_realloc",
- );
- let deprecated_program_id = create_program(
- &bank,
- &bpf_loader_deprecated::id(),
- "solana_sbf_rust_deprecated_loader",
- );
- let account_keypair = Keypair::new();
- let mint_pubkey = mint_keypair.pubkey();
- let account_metas = vec![
- AccountMeta::new(mint_pubkey, true),
- AccountMeta::new(account_keypair.pubkey(), false),
- AccountMeta::new_readonly(
- if deprecated_callee {
- deprecated_program_id
- } else {
- realloc_program_id
- },
- false,
- ),
- AccountMeta::new_readonly(
- if deprecated_caller {
- deprecated_program_id
- } else {
- invoke_program_id
- },
- false,
- ),
- ];
- // This tests the case where a caller extends an account beyond the original
- // data length. The callee should see the extended data (asserted in the
- // callee program, not here).
- let mut account = AccountSharedData::new(42, 0, &account_metas[3].pubkey);
- account.set_data(b"foo".to_vec());
- bank.store_account(&account_keypair.pubkey(), &account);
- let mut instruction_data = vec![TEST_CPI_ACCOUNT_UPDATE_CALLER_GROWS];
- instruction_data.extend_from_slice(b"bar");
- let instruction = Instruction::new_with_bytes(
- account_metas[3].pubkey,
- &instruction_data,
- account_metas.clone(),
- );
- let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
- if deprecated_caller {
- assert_eq!(
- result.unwrap_err().unwrap(),
- TransactionError::InstructionError(
- 0,
- if stricter_abi_and_runtime_constraints {
- InstructionError::ProgramFailedToComplete
- } else {
- InstructionError::ModifiedProgramId
- }
- )
- );
- } else {
- assert!(result.is_ok(), "{result:?}");
- let account = bank.get_account(&account_keypair.pubkey()).unwrap();
- // "bar" here was copied from the realloc region
- assert_eq!(account.data(), b"foobar");
- }
- // This tests the case where a callee extends an account beyond the original
- // data length. The caller should see the extended data where the realloc
- // region contains the new data. In this test the callee owns the account,
- // the caller can't write but the CPI glue still updates correctly.
- let mut account = AccountSharedData::new(42, 0, &account_metas[2].pubkey);
- account.set_data(b"foo".to_vec());
- bank.store_account(&account_keypair.pubkey(), &account);
- let mut instruction_data = vec![TEST_CPI_ACCOUNT_UPDATE_CALLEE_GROWS];
- instruction_data.extend_from_slice(b"bar");
- let instruction = Instruction::new_with_bytes(
- account_metas[3].pubkey,
- &instruction_data,
- account_metas.clone(),
- );
- let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
- if deprecated_callee {
- assert!(result.is_ok(), "{result:?}");
- let account = bank.get_account(&account_keypair.pubkey()).unwrap();
- // deprecated_callee is incapable of resizing accounts
- assert_eq!(account.data(), b"foo");
- } else if deprecated_caller {
- assert_eq!(
- result.unwrap_err().unwrap(),
- TransactionError::InstructionError(
- 0,
- if stricter_abi_and_runtime_constraints {
- InstructionError::InvalidRealloc
- } else {
- InstructionError::AccountDataSizeChanged
- }
- )
- );
- } else {
- assert!(result.is_ok(), "{result:?}");
- let account = bank.get_account(&account_keypair.pubkey()).unwrap();
- // "bar" here was copied from the realloc region
- assert_eq!(account.data(), b"foobar");
- }
- // This tests the case where a callee shrinks an account, the caller data
- // slice must be truncated accordingly and post_len..original_data_len must
- // be zeroed (zeroing is checked in the invoked program not here). Same as
- // above, the callee owns the account but the changes are still reflected in
- // the caller even if things are readonly from the caller's POV.
- let mut account = AccountSharedData::new(42, 0, &account_metas[2].pubkey);
- account.set_data(b"foobar".to_vec());
- bank.store_account(&account_keypair.pubkey(), &account);
- let mut instruction_data = vec![
- TEST_CPI_ACCOUNT_UPDATE_CALLEE_SHRINKS_SMALLER_THAN_ORIGINAL_LEN,
- stricter_abi_and_runtime_constraints as u8,
- ];
- instruction_data.extend_from_slice(4usize.to_le_bytes().as_ref());
- let instruction = Instruction::new_with_bytes(
- account_metas[3].pubkey,
- &instruction_data,
- account_metas.clone(),
- );
- let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
- if deprecated_callee {
- assert!(result.is_ok(), "{result:?}");
- let account = bank.get_account(&account_keypair.pubkey()).unwrap();
- // deprecated_callee is incapable of resizing accounts
- assert_eq!(account.data(), b"foobar");
- } else if deprecated_caller {
- assert_eq!(
- result.unwrap_err().unwrap(),
- TransactionError::InstructionError(
- 0,
- if stricter_abi_and_runtime_constraints && deprecated_callee {
- InstructionError::InvalidRealloc
- } else {
- InstructionError::AccountDataSizeChanged
- }
- )
- );
- } else {
- assert!(result.is_ok(), "{result:?}");
- let account = bank.get_account(&account_keypair.pubkey()).unwrap();
- assert_eq!(account.data(), b"foob");
- }
- // This tests the case where the program extends an account, then calls
- // itself and in the inner call it shrinks the account to a size that is
- // still larger than the original size. The account data must be set to the
- // correct value in the caller frame, and the realloc region must be zeroed
- // (again tested in the invoked program).
- let mut account = AccountSharedData::new(42, 0, &account_metas[3].pubkey);
- account.set_data(b"foo".to_vec());
- bank.store_account(&account_keypair.pubkey(), &account);
- let mut instruction_data = vec![
- TEST_CPI_ACCOUNT_UPDATE_CALLER_GROWS_CALLEE_SHRINKS,
- stricter_abi_and_runtime_constraints as u8,
- ];
- // realloc to "foobazbad" then shrink to "foobazb"
- instruction_data.extend_from_slice(7usize.to_le_bytes().as_ref());
- instruction_data.extend_from_slice(b"bazbad");
- let instruction = Instruction::new_with_bytes(
- account_metas[3].pubkey,
- &instruction_data,
- account_metas.clone(),
- );
- let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
- if deprecated_caller {
- assert_eq!(
- result.unwrap_err().unwrap(),
- TransactionError::InstructionError(
- 0,
- if stricter_abi_and_runtime_constraints {
- InstructionError::ProgramFailedToComplete
- } else {
- InstructionError::ModifiedProgramId
- }
- )
- );
- } else {
- assert!(result.is_ok(), "{result:?}");
- let account = bank.get_account(&account_keypair.pubkey()).unwrap();
- assert_eq!(account.data(), b"foobazb");
- }
- // Similar to the test above, but this time the nested invocation shrinks to
- // _below_ the original data length. Both the spare capacity in the account
- // data _end_ the realloc region must be zeroed.
- let mut account = AccountSharedData::new(42, 0, &account_metas[3].pubkey);
- account.set_data(b"foo".to_vec());
- bank.store_account(&account_keypair.pubkey(), &account);
- let mut instruction_data = vec![
- TEST_CPI_ACCOUNT_UPDATE_CALLER_GROWS_CALLEE_SHRINKS,
- stricter_abi_and_runtime_constraints as u8,
- ];
- // realloc to "foobazbad" then shrink to "f"
- instruction_data.extend_from_slice(1usize.to_le_bytes().as_ref());
- instruction_data.extend_from_slice(b"bazbad");
- let instruction = Instruction::new_with_bytes(
- account_metas[3].pubkey,
- &instruction_data,
- account_metas.clone(),
- );
- let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
- if deprecated_caller {
- assert_eq!(
- result.unwrap_err().unwrap(),
- TransactionError::InstructionError(
- 0,
- if stricter_abi_and_runtime_constraints {
- InstructionError::ProgramFailedToComplete
- } else {
- InstructionError::ModifiedProgramId
- }
- )
- );
- } else {
- assert!(result.is_ok(), "{result:?}");
- let account = bank.get_account(&account_keypair.pubkey()).unwrap();
- assert_eq!(account.data(), b"f");
- }
- }
- }
- #[test]
- #[cfg(any(feature = "sbf_c", feature = "sbf_rust"))]
- fn test_cpi_invalid_account_info_pointers() {
- agave_logger::setup();
- let GenesisConfigInfo {
- genesis_config,
- mint_keypair,
- ..
- } = create_genesis_config(100_123_456_789);
- let bank = Bank::new_for_tests(&genesis_config);
- let (bank, bank_forks) = bank.wrap_with_bank_forks_for_tests();
- let mut bank_client = BankClient::new_shared(bank);
- let authority_keypair = Keypair::new();
- let account_keypair = Keypair::new();
- let mint_pubkey = mint_keypair.pubkey();
- let mut account_metas = vec![
- AccountMeta::new(mint_pubkey, true),
- AccountMeta::new(account_keypair.pubkey(), false),
- ];
- let mut program_ids: Vec<Pubkey> = Vec::with_capacity(2);
- #[allow(unused_mut)]
- let mut bank;
- #[cfg(feature = "sbf_rust")]
- {
- let (new_bank, invoke_program_id) = load_program_of_loader_v4(
- &mut bank_client,
- &bank_forks,
- &mint_keypair,
- &authority_keypair,
- "solana_sbf_rust_invoke",
- );
- account_metas.push(AccountMeta::new_readonly(invoke_program_id, false));
- program_ids.push(invoke_program_id);
- #[allow(unused)]
- {
- bank = new_bank;
- }
- }
- #[cfg(feature = "sbf_c")]
- {
- let (new_bank, c_invoke_program_id) = load_program_of_loader_v4(
- &mut bank_client,
- &bank_forks,
- &mint_keypair,
- &authority_keypair,
- "invoke",
- );
- account_metas.push(AccountMeta::new_readonly(c_invoke_program_id, false));
- program_ids.push(c_invoke_program_id);
- #[allow(unused)]
- {
- bank = new_bank;
- }
- }
- for invoke_program_id in &program_ids {
- for ix in [
- TEST_CPI_INVALID_KEY_POINTER,
- TEST_CPI_INVALID_LAMPORTS_POINTER,
- TEST_CPI_INVALID_OWNER_POINTER,
- TEST_CPI_INVALID_DATA_POINTER,
- ] {
- let account = AccountSharedData::new(42, 5, invoke_program_id);
- bank.store_account(&account_keypair.pubkey(), &account);
- let instruction = Instruction::new_with_bytes(
- *invoke_program_id,
- &[ix, 42, 42, 42],
- account_metas.clone(),
- );
- let message = Message::new(&[instruction], Some(&mint_pubkey));
- let tx = Transaction::new(&[&mint_keypair], message.clone(), bank.last_blockhash());
- let (result, _, logs, _) = process_transaction_and_record_inner(&bank, tx);
- assert!(result.is_err(), "{result:?}");
- assert!(
- logs.iter().any(|log| log.contains("Invalid pointer")),
- "{logs:?}"
- );
- }
- }
- }
- #[test]
- #[cfg(feature = "sbf_rust")]
- fn test_deplete_cost_meter_with_access_violation() {
- agave_logger::setup();
- let GenesisConfigInfo {
- genesis_config,
- mint_keypair,
- ..
- } = create_genesis_config(100_123_456_789);
- let bank = Bank::new_for_tests(&genesis_config);
- let (bank, bank_forks) = bank.wrap_with_bank_forks_for_tests();
- let mut bank_client = BankClient::new_shared(bank.clone());
- let authority_keypair = Keypair::new();
- let (bank, invoke_program_id) = load_program_of_loader_v4(
- &mut bank_client,
- bank_forks.as_ref(),
- &mint_keypair,
- &authority_keypair,
- "solana_sbf_rust_invoke",
- );
- let account_keypair = Keypair::new();
- let mint_pubkey = mint_keypair.pubkey();
- let account_metas = vec![
- AccountMeta::new(mint_pubkey, true),
- AccountMeta::new(account_keypair.pubkey(), false),
- AccountMeta::new_readonly(invoke_program_id, false),
- ];
- let mut instruction_data = vec![TEST_WRITE_ACCOUNT, 2];
- instruction_data.extend_from_slice(3usize.to_le_bytes().as_ref());
- instruction_data.push(42);
- let instruction =
- Instruction::new_with_bytes(invoke_program_id, &instruction_data, account_metas.clone());
- let compute_unit_limit = 10_000u32;
- let message = Message::new(
- &[
- ComputeBudgetInstruction::set_compute_unit_limit(compute_unit_limit),
- instruction,
- ],
- Some(&mint_keypair.pubkey()),
- );
- let tx = Transaction::new(&[&mint_keypair], message, bank.last_blockhash());
- let result = load_execute_and_commit_transaction(&bank, tx).unwrap();
- assert_eq!(
- result.status.unwrap_err(),
- TransactionError::InstructionError(1, InstructionError::ReadonlyDataModified)
- );
- // all compute unit limit should be consumed due to SBF VM error
- assert_eq!(result.executed_units, u64::from(compute_unit_limit));
- }
- #[test]
- #[cfg(feature = "sbf_rust")]
- fn test_program_sbf_deplete_cost_meter_with_divide_by_zero() {
- agave_logger::setup();
- let GenesisConfigInfo {
- genesis_config,
- mint_keypair,
- ..
- } = create_genesis_config(50);
- let bank = Bank::new_for_tests(&genesis_config);
- let (bank, bank_forks) = bank.wrap_with_bank_forks_for_tests();
- let mut bank_client = BankClient::new_shared(bank.clone());
- let authority_keypair = Keypair::new();
- let (bank, program_id) = load_program_of_loader_v4(
- &mut bank_client,
- bank_forks.as_ref(),
- &mint_keypair,
- &authority_keypair,
- "solana_sbf_rust_divide_by_zero",
- );
- let instruction = Instruction::new_with_bytes(program_id, &[], vec![]);
- let compute_unit_limit = 10_000;
- let message = Message::new(
- &[
- ComputeBudgetInstruction::set_compute_unit_limit(compute_unit_limit),
- instruction,
- ],
- Some(&mint_keypair.pubkey()),
- );
- let tx = Transaction::new(&[&mint_keypair], message, bank.last_blockhash());
- let result = load_execute_and_commit_transaction(&bank, tx).unwrap();
- assert_eq!(
- result.status.unwrap_err(),
- TransactionError::InstructionError(1, InstructionError::ProgramFailedToComplete)
- );
- // all compute unit limit should be consumed due to SBF VM error
- assert_eq!(result.executed_units, u64::from(compute_unit_limit));
- }
- #[test]
- #[cfg(feature = "sbf_rust")]
- fn test_deny_access_beyond_current_length() {
- agave_logger::setup();
- let GenesisConfigInfo {
- genesis_config,
- mint_keypair,
- ..
- } = create_genesis_config(100_123_456_789);
- for stricter_abi_and_runtime_constraints in [false, true] {
- let mut bank = Bank::new_for_tests(&genesis_config);
- let feature_set = Arc::make_mut(&mut bank.feature_set);
- // by default test banks have all features enabled, so we only need to
- // disable when needed
- if !stricter_abi_and_runtime_constraints {
- feature_set.deactivate(&feature_set::stricter_abi_and_runtime_constraints::id());
- feature_set.deactivate(&feature_set::account_data_direct_mapping::id());
- }
- let (bank, bank_forks) = bank.wrap_with_bank_forks_for_tests();
- let mut bank_client = BankClient::new_shared(bank);
- let authority_keypair = Keypair::new();
- let (bank, invoke_program_id) = load_program_of_loader_v4(
- &mut bank_client,
- &bank_forks,
- &mint_keypair,
- &authority_keypair,
- "solana_sbf_rust_invoke",
- );
- let account = AccountSharedData::new(42, 0, &invoke_program_id);
- let readonly_account_keypair = Keypair::new();
- let writable_account_keypair = Keypair::new();
- bank.store_account(&readonly_account_keypair.pubkey(), &account);
- bank.store_account(&writable_account_keypair.pubkey(), &account);
- let mint_pubkey = mint_keypair.pubkey();
- let account_metas = vec![
- AccountMeta::new(mint_pubkey, true),
- AccountMeta::new_readonly(readonly_account_keypair.pubkey(), false),
- AccountMeta::new(writable_account_keypair.pubkey(), false),
- AccountMeta::new_readonly(invoke_program_id, false),
- ];
- for (instruction_account_index, expected_error) in [
- (1, InstructionError::AccountDataTooSmall),
- (2, InstructionError::InvalidRealloc),
- ] {
- let mut instruction_data = vec![TEST_READ_ACCOUNT, instruction_account_index];
- instruction_data.extend_from_slice(3usize.to_le_bytes().as_ref());
- let instruction = Instruction::new_with_bytes(
- invoke_program_id,
- &instruction_data,
- account_metas.clone(),
- );
- let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
- if stricter_abi_and_runtime_constraints {
- assert_eq!(
- result.unwrap_err().unwrap(),
- TransactionError::InstructionError(0, expected_error)
- );
- } else {
- result.unwrap();
- }
- }
- }
- }
- #[test]
- #[cfg(feature = "sbf_rust")]
- fn test_deny_executable_write() {
- agave_logger::setup();
- let GenesisConfigInfo {
- genesis_config,
- mint_keypair,
- ..
- } = create_genesis_config(100_123_456_789);
- for stricter_abi_and_runtime_constraints in [false, true] {
- let mut bank = Bank::new_for_tests(&genesis_config);
- let feature_set = Arc::make_mut(&mut bank.feature_set);
- // by default test banks have all features enabled, so we only need to
- // disable when needed
- if !stricter_abi_and_runtime_constraints {
- feature_set.deactivate(&feature_set::stricter_abi_and_runtime_constraints::id());
- feature_set.deactivate(&feature_set::account_data_direct_mapping::id());
- }
- let (bank, bank_forks) = bank.wrap_with_bank_forks_for_tests();
- let mut bank_client = BankClient::new_shared(bank);
- let authority_keypair = Keypair::new();
- let (_bank, invoke_program_id) = load_program_of_loader_v4(
- &mut bank_client,
- &bank_forks,
- &mint_keypair,
- &authority_keypair,
- "solana_sbf_rust_invoke",
- );
- let account_keypair = Keypair::new();
- let mint_pubkey = mint_keypair.pubkey();
- let account_metas = vec![
- AccountMeta::new(mint_pubkey, true),
- AccountMeta::new(account_keypair.pubkey(), false),
- AccountMeta::new_readonly(invoke_program_id, false),
- ];
- let mut instruction_data = vec![TEST_WRITE_ACCOUNT, 2];
- instruction_data.extend_from_slice(3usize.to_le_bytes().as_ref());
- instruction_data.push(42);
- let instruction = Instruction::new_with_bytes(
- invoke_program_id,
- &instruction_data,
- account_metas.clone(),
- );
- let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
- assert_eq!(
- result.unwrap_err().unwrap(),
- TransactionError::InstructionError(0, InstructionError::ReadonlyDataModified)
- );
- }
- }
- #[test]
- fn test_update_callee_account() {
- // Test that fn update_callee_account() works and we are updating the callee account on CPI.
- agave_logger::setup();
- let GenesisConfigInfo {
- genesis_config,
- mint_keypair,
- ..
- } = create_genesis_config(100_123_456_789);
- for stricter_abi_and_runtime_constraints in [false, true] {
- let mut bank = Bank::new_for_tests(&genesis_config);
- let feature_set = Arc::make_mut(&mut bank.feature_set);
- // by default test banks have all features enabled, so we only need to
- // disable when needed
- if !stricter_abi_and_runtime_constraints {
- feature_set.deactivate(&feature_set::stricter_abi_and_runtime_constraints::id());
- feature_set.deactivate(&feature_set::account_data_direct_mapping::id());
- }
- let (bank, bank_forks) = bank.wrap_with_bank_forks_for_tests();
- let mut bank_client = BankClient::new_shared(bank.clone());
- let authority_keypair = Keypair::new();
- let (bank, invoke_program_id) = load_program_of_loader_v4(
- &mut bank_client,
- &bank_forks,
- &mint_keypair,
- &authority_keypair,
- "solana_sbf_rust_invoke",
- );
- let account_keypair = Keypair::new();
- let mint_pubkey = mint_keypair.pubkey();
- let account_metas = vec![
- AccountMeta::new(mint_pubkey, true),
- AccountMeta::new(account_keypair.pubkey(), false),
- AccountMeta::new_readonly(invoke_program_id, false),
- ];
- // I. do CPI with account in read only (separate code path with stricter_abi_and_runtime_constraints)
- let mut account = AccountSharedData::new(42, 10240, &invoke_program_id);
- let data: Vec<u8> = (0..10240).map(|n| n as u8).collect();
- account.set_data(data);
- bank.store_account(&account_keypair.pubkey(), &account);
- let mut instruction_data = vec![TEST_CALLEE_ACCOUNT_UPDATES, 0, 0];
- instruction_data.extend_from_slice(20480usize.to_le_bytes().as_ref());
- instruction_data.extend_from_slice(0usize.to_le_bytes().as_ref());
- instruction_data.extend_from_slice(16384usize.to_le_bytes().as_ref());
- // instruction data for inner CPI (2x)
- instruction_data.extend_from_slice(&[TEST_CALLEE_ACCOUNT_UPDATES, 0, 0]);
- instruction_data.extend_from_slice(0usize.to_le_bytes().as_ref());
- instruction_data.extend_from_slice(0usize.to_le_bytes().as_ref());
- instruction_data.extend_from_slice(0usize.to_le_bytes().as_ref());
- instruction_data.extend_from_slice(&[TEST_CALLEE_ACCOUNT_UPDATES, 0, 0]);
- instruction_data.extend_from_slice(0usize.to_le_bytes().as_ref());
- instruction_data.extend_from_slice(0usize.to_le_bytes().as_ref());
- instruction_data.extend_from_slice(0usize.to_le_bytes().as_ref());
- let instruction = Instruction::new_with_bytes(
- invoke_program_id,
- &instruction_data,
- account_metas.clone(),
- );
- let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
- assert!(result.is_ok());
- let data = bank_client
- .get_account_data(&account_keypair.pubkey())
- .unwrap()
- .unwrap();
- assert_eq!(data.len(), 20480);
- data.iter().enumerate().for_each(|(i, v)| {
- let expected = match i {
- ..=10240 => i as u8,
- 16384 => 0xe5,
- _ => 0,
- };
- assert_eq!(*v, expected, "offset:{i} {v:#x} != {expected:#x}");
- });
- // II. do CPI with account with resize to smaller and write
- let mut account = AccountSharedData::new(42, 10240, &invoke_program_id);
- let data: Vec<u8> = (0..10240).map(|n| n as u8).collect();
- account.set_data(data);
- bank.store_account(&account_keypair.pubkey(), &account);
- let mut instruction_data = vec![TEST_CALLEE_ACCOUNT_UPDATES, 1, 0];
- instruction_data.extend_from_slice(20480usize.to_le_bytes().as_ref());
- instruction_data.extend_from_slice(0usize.to_le_bytes().as_ref());
- instruction_data.extend_from_slice(16384usize.to_le_bytes().as_ref());
- // instruction data for inner CPI
- instruction_data.extend_from_slice(&[TEST_CALLEE_ACCOUNT_UPDATES, 0, 0]);
- instruction_data.extend_from_slice(19480usize.to_le_bytes().as_ref());
- instruction_data.extend_from_slice(0usize.to_le_bytes().as_ref());
- instruction_data.extend_from_slice(8129usize.to_le_bytes().as_ref());
- let instruction = Instruction::new_with_bytes(
- invoke_program_id,
- &instruction_data,
- account_metas.clone(),
- );
- let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
- assert!(result.is_ok());
- let data = bank_client
- .get_account_data(&account_keypair.pubkey())
- .unwrap()
- .unwrap();
- assert_eq!(data.len(), 19480);
- data.iter().enumerate().for_each(|(i, v)| {
- let expected = match i {
- 8129 => (i as u8) ^ 0xe5,
- ..=10240 => i as u8,
- 16384 => 0xe5,
- _ => 0,
- };
- assert_eq!(*v, expected, "offset:{i} {v:#x} != {expected:#x}");
- });
- // III. do CPI with account with resize to larger and write
- let mut account = AccountSharedData::new(42, 10240, &invoke_program_id);
- let data: Vec<u8> = (0..10240).map(|n| n as u8).collect();
- account.set_data(data);
- bank.store_account(&account_keypair.pubkey(), &account);
- let mut instruction_data = vec![TEST_CALLEE_ACCOUNT_UPDATES, 1, 0];
- instruction_data.extend_from_slice(16384usize.to_le_bytes().as_ref());
- instruction_data.extend_from_slice(0usize.to_le_bytes().as_ref());
- instruction_data.extend_from_slice(16384usize.to_le_bytes().as_ref());
- // instruction data for inner CPI
- instruction_data.extend_from_slice(&[TEST_CALLEE_ACCOUNT_UPDATES, 0, 0]);
- instruction_data.extend_from_slice(20480usize.to_le_bytes().as_ref());
- instruction_data.extend_from_slice(0usize.to_le_bytes().as_ref());
- instruction_data.extend_from_slice(16385usize.to_le_bytes().as_ref());
- let instruction = Instruction::new_with_bytes(
- invoke_program_id,
- &instruction_data,
- account_metas.clone(),
- );
- let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
- assert!(result.is_ok());
- let data = bank_client
- .get_account_data(&account_keypair.pubkey())
- .unwrap()
- .unwrap();
- assert_eq!(data.len(), 20480);
- data.iter().enumerate().for_each(|(i, v)| {
- let expected = match i {
- ..=10240 => i as u8,
- 16384 | 16385 => 0xe5,
- _ => 0,
- };
- assert_eq!(*v, expected, "offset:{i} {v:#x} != {expected:#x}");
- });
- // IV. do CPI with account with resize to larger and write
- let mut account = AccountSharedData::new(42, 10240, &invoke_program_id);
- let data: Vec<u8> = (0..10240).map(|n| n as u8).collect();
- account.set_data(data);
- bank.store_account(&account_keypair.pubkey(), &account);
- let mut instruction_data = vec![TEST_CALLEE_ACCOUNT_UPDATES, 1, 0];
- instruction_data.extend_from_slice(16384usize.to_le_bytes().as_ref());
- instruction_data.extend_from_slice(0usize.to_le_bytes().as_ref());
- instruction_data.extend_from_slice(16384usize.to_le_bytes().as_ref());
- // instruction data for inner CPI (2x)
- instruction_data.extend_from_slice(&[TEST_CALLEE_ACCOUNT_UPDATES, 1, 0]);
- instruction_data.extend_from_slice(0usize.to_le_bytes().as_ref());
- instruction_data.extend_from_slice(0usize.to_le_bytes().as_ref());
- instruction_data.extend_from_slice(0usize.to_le_bytes().as_ref());
- instruction_data.extend_from_slice(&[TEST_CALLEE_ACCOUNT_UPDATES, 1, 0]);
- instruction_data.extend_from_slice(0usize.to_le_bytes().as_ref());
- instruction_data.extend_from_slice(0usize.to_le_bytes().as_ref());
- instruction_data.extend_from_slice(0usize.to_le_bytes().as_ref());
- // instruction data for inner CPI
- instruction_data.extend_from_slice(&[TEST_CALLEE_ACCOUNT_UPDATES, 0, 0]);
- instruction_data.extend_from_slice(20480usize.to_le_bytes().as_ref());
- instruction_data.extend_from_slice(0usize.to_le_bytes().as_ref());
- instruction_data.extend_from_slice(16385usize.to_le_bytes().as_ref());
- let instruction = Instruction::new_with_bytes(
- invoke_program_id,
- &instruction_data,
- account_metas.clone(),
- );
- let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
- assert!(result.is_ok());
- let data = bank_client
- .get_account_data(&account_keypair.pubkey())
- .unwrap()
- .unwrap();
- assert_eq!(data.len(), 20480);
- data.iter().enumerate().for_each(|(i, v)| {
- let expected = match i {
- ..=10240 => i as u8,
- 16384 | 16385 => 0xe5,
- _ => 0,
- };
- assert_eq!(*v, expected, "offset:{i} {v:#x} != {expected:#x}");
- });
- // V. clone data, modify and CPI
- let mut account = AccountSharedData::new(42, 10240, &invoke_program_id);
- let data: Vec<u8> = (0..10240).map(|n| n as u8).collect();
- account.set_data(data);
- bank.store_account(&account_keypair.pubkey(), &account);
- let mut instruction_data = vec![TEST_CALLEE_ACCOUNT_UPDATES, 1, 1];
- instruction_data.extend_from_slice(0usize.to_le_bytes().as_ref());
- instruction_data.extend_from_slice(0usize.to_le_bytes().as_ref());
- instruction_data.extend_from_slice(8190usize.to_le_bytes().as_ref());
- // instruction data for inner CPI
- instruction_data.extend_from_slice(&[TEST_CALLEE_ACCOUNT_UPDATES, 1, 0]);
- instruction_data.extend_from_slice(0usize.to_le_bytes().as_ref());
- instruction_data.extend_from_slice(0usize.to_le_bytes().as_ref());
- instruction_data.extend_from_slice(8191usize.to_le_bytes().as_ref());
- let instruction = Instruction::new_with_bytes(
- invoke_program_id,
- &instruction_data,
- account_metas.clone(),
- );
- let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
- if stricter_abi_and_runtime_constraints {
- // changing the data pointer is not permitted
- assert!(result.is_err());
- } else {
- assert!(result.is_ok());
- let data = bank_client
- .get_account_data(&account_keypair.pubkey())
- .unwrap()
- .unwrap();
- assert_eq!(data.len(), 10240);
- data.iter().enumerate().for_each(|(i, v)| {
- let expected = match i {
- // since the data is was cloned, the write to 8191 was lost
- 8190 => (i as u8) ^ 0xe5,
- ..=10240 => i as u8,
- _ => 0,
- };
- assert_eq!(*v, expected, "offset:{i} {v:#x} != {expected:#x}");
- });
- }
- }
- }
- #[test]
- fn test_account_info_in_account() {
- agave_logger::setup();
- let GenesisConfigInfo {
- genesis_config,
- mint_keypair,
- ..
- } = create_genesis_config(100_123_456_789);
- let mut programs = Vec::new();
- #[cfg(feature = "sbf_c")]
- {
- programs.push("invoke");
- }
- #[cfg(feature = "sbf_rust")]
- {
- programs.push("solana_sbf_rust_invoke");
- }
- for program in programs {
- for stricter_abi_and_runtime_constraints in [false, true] {
- let mut bank = Bank::new_for_tests(&genesis_config);
- let feature_set = Arc::make_mut(&mut bank.feature_set);
- // by default test banks have all features enabled, so we only need to
- // disable when needed
- if !stricter_abi_and_runtime_constraints {
- feature_set.deactivate(&feature_set::stricter_abi_and_runtime_constraints::id());
- feature_set.deactivate(&feature_set::account_data_direct_mapping::id());
- }
- let (bank, bank_forks) = bank.wrap_with_bank_forks_for_tests();
- let mut bank_client = BankClient::new_shared(bank.clone());
- let authority_keypair = Keypair::new();
- let (bank, invoke_program_id) = load_program_of_loader_v4(
- &mut bank_client,
- &bank_forks,
- &mint_keypair,
- &authority_keypair,
- program,
- );
- let account_keypair = Keypair::new();
- let mint_pubkey = mint_keypair.pubkey();
- let account_metas = vec![
- AccountMeta::new(mint_pubkey, true),
- AccountMeta::new(account_keypair.pubkey(), false),
- AccountMeta::new_readonly(invoke_program_id, false),
- ];
- let mut instruction_data = vec![TEST_ACCOUNT_INFO_IN_ACCOUNT];
- instruction_data.extend_from_slice(32usize.to_le_bytes().as_ref());
- let instruction =
- Instruction::new_with_bytes(invoke_program_id, &instruction_data, account_metas);
- let account = AccountSharedData::new(42, 10240, &invoke_program_id);
- bank.store_account(&account_keypair.pubkey(), &account);
- let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
- if stricter_abi_and_runtime_constraints {
- assert!(result.is_err());
- } else {
- assert!(result.is_ok());
- }
- }
- }
- }
- #[test]
- fn test_account_info_rc_in_account() {
- agave_logger::setup();
- let GenesisConfigInfo {
- genesis_config,
- mint_keypair,
- ..
- } = create_genesis_config(100_123_456_789);
- for stricter_abi_and_runtime_constraints in [false, true] {
- let mut bank = Bank::new_for_tests(&genesis_config);
- let feature_set = Arc::make_mut(&mut bank.feature_set);
- // by default test banks have all features enabled, so we only need to
- // disable when needed
- if !stricter_abi_and_runtime_constraints {
- feature_set.deactivate(&feature_set::stricter_abi_and_runtime_constraints::id());
- feature_set.deactivate(&feature_set::account_data_direct_mapping::id());
- }
- let (bank, bank_forks) = bank.wrap_with_bank_forks_for_tests();
- let mut bank_client = BankClient::new_shared(bank.clone());
- let authority_keypair = Keypair::new();
- let (bank, invoke_program_id) = load_program_of_loader_v4(
- &mut bank_client,
- &bank_forks,
- &mint_keypair,
- &authority_keypair,
- "solana_sbf_rust_invoke",
- );
- let account_keypair = Keypair::new();
- let mint_pubkey = mint_keypair.pubkey();
- let account_metas = vec![
- AccountMeta::new(mint_pubkey, true),
- AccountMeta::new(account_keypair.pubkey(), false),
- AccountMeta::new_readonly(invoke_program_id, false),
- ];
- let instruction_data = vec![TEST_ACCOUNT_INFO_LAMPORTS_RC, 0, 0, 0];
- let instruction = Instruction::new_with_bytes(
- invoke_program_id,
- &instruction_data,
- account_metas.clone(),
- );
- let account = AccountSharedData::new(42, 10240, &invoke_program_id);
- bank.store_account(&account_keypair.pubkey(), &account);
- let message = Message::new(&[instruction], Some(&mint_pubkey));
- let tx = Transaction::new(&[&mint_keypair], message.clone(), bank.last_blockhash());
- let (result, _, logs, _) = process_transaction_and_record_inner(&bank, tx);
- if stricter_abi_and_runtime_constraints {
- assert!(
- logs.last().unwrap().ends_with(" failed: Invalid pointer"),
- "{logs:?}"
- );
- assert!(result.is_err());
- } else {
- assert!(result.is_ok(), "{logs:?}");
- }
- let instruction_data = vec![TEST_ACCOUNT_INFO_DATA_RC, 0, 0, 0];
- let instruction =
- Instruction::new_with_bytes(invoke_program_id, &instruction_data, account_metas);
- let account = AccountSharedData::new(42, 10240, &invoke_program_id);
- bank.store_account(&account_keypair.pubkey(), &account);
- let message = Message::new(&[instruction], Some(&mint_pubkey));
- let tx = Transaction::new(&[&mint_keypair], message.clone(), bank.last_blockhash());
- let (result, _, logs, _) = process_transaction_and_record_inner(&bank, tx);
- if stricter_abi_and_runtime_constraints {
- assert!(
- logs.last().unwrap().ends_with(" failed: Invalid pointer"),
- "{logs:?}"
- );
- assert!(result.is_err());
- } else {
- assert!(result.is_ok(), "{logs:?}");
- }
- }
- }
- #[test]
- fn test_clone_account_data() {
- // Test cloning account data works as expect with
- agave_logger::setup();
- let GenesisConfigInfo {
- genesis_config,
- mint_keypair,
- ..
- } = create_genesis_config(100_123_456_789);
- let mut bank = Bank::new_for_tests(&genesis_config);
- let feature_set = Arc::make_mut(&mut bank.feature_set);
- feature_set.deactivate(&feature_set::stricter_abi_and_runtime_constraints::id());
- feature_set.deactivate(&feature_set::account_data_direct_mapping::id());
- let (bank, bank_forks) = bank.wrap_with_bank_forks_for_tests();
- let mut bank_client = BankClient::new_shared(bank.clone());
- let authority_keypair = Keypair::new();
- let (_bank, invoke_program_id) = load_program_of_loader_v4(
- &mut bank_client,
- &bank_forks,
- &mint_keypair,
- &authority_keypair,
- "solana_sbf_rust_invoke",
- );
- let (bank, invoke_program_id2) = load_program_of_loader_v4(
- &mut bank_client,
- &bank_forks,
- &mint_keypair,
- &authority_keypair,
- "solana_sbf_rust_invoke",
- );
- let account_keypair = Keypair::new();
- let mint_pubkey = mint_keypair.pubkey();
- let account_metas = vec![
- AccountMeta::new(mint_pubkey, true),
- AccountMeta::new(account_keypair.pubkey(), false),
- AccountMeta::new_readonly(invoke_program_id2, false),
- AccountMeta::new_readonly(invoke_program_id, false),
- ];
- // I. clone data and CPI; modify data in callee.
- // Now the original data in the caller is unmodified, and we get a "instruction modified data of an account it does not own"
- // error in the caller
- let mut account = AccountSharedData::new(42, 10240, &invoke_program_id2);
- let data: Vec<u8> = (0..10240).map(|n| n as u8).collect();
- account.set_data(data);
- bank.store_account(&account_keypair.pubkey(), &account);
- let mut instruction_data = vec![TEST_CALLEE_ACCOUNT_UPDATES, 1, 1];
- instruction_data.extend_from_slice(0usize.to_le_bytes().as_ref());
- instruction_data.extend_from_slice(0usize.to_le_bytes().as_ref());
- instruction_data.extend_from_slice(0usize.to_le_bytes().as_ref());
- // instruction data for inner CPI: modify account
- instruction_data.extend_from_slice(&[TEST_CALLEE_ACCOUNT_UPDATES, 0, 0]);
- instruction_data.extend_from_slice(0usize.to_le_bytes().as_ref());
- instruction_data.extend_from_slice(0usize.to_le_bytes().as_ref());
- instruction_data.extend_from_slice(8190usize.to_le_bytes().as_ref());
- let instruction =
- Instruction::new_with_bytes(invoke_program_id, &instruction_data, account_metas.clone());
- let message = Message::new(&[instruction], Some(&mint_pubkey));
- let tx = Transaction::new(&[&mint_keypair], message.clone(), bank.last_blockhash());
- let (result, _, logs, _) = process_transaction_and_record_inner(&bank, tx);
- assert!(result.is_err(), "{result:?}");
- let error = format!(
- "Program {invoke_program_id} failed: instruction modified data of an account it does not \
- own"
- );
- assert!(logs.iter().any(|log| log.contains(&error)), "{logs:?}");
- // II. clone data, modify and then CPI
- // The deserialize checks should verify that we're not allowed to modify an account we don't own, even though
- // we have only modified a copy of the data. Fails in caller
- let mut account = AccountSharedData::new(42, 10240, &invoke_program_id2);
- let data: Vec<u8> = (0..10240).map(|n| n as u8).collect();
- account.set_data(data);
- bank.store_account(&account_keypair.pubkey(), &account);
- let mut instruction_data = vec![TEST_CALLEE_ACCOUNT_UPDATES, 1, 1];
- instruction_data.extend_from_slice(0usize.to_le_bytes().as_ref());
- instruction_data.extend_from_slice(8190usize.to_le_bytes().as_ref());
- instruction_data.extend_from_slice(0usize.to_le_bytes().as_ref());
- // instruction data for inner CPI
- instruction_data.extend_from_slice(&[TEST_CALLEE_ACCOUNT_UPDATES, 0, 0]);
- instruction_data.extend_from_slice(0usize.to_le_bytes().as_ref());
- instruction_data.extend_from_slice(0usize.to_le_bytes().as_ref());
- instruction_data.extend_from_slice(0usize.to_le_bytes().as_ref());
- let instruction =
- Instruction::new_with_bytes(invoke_program_id, &instruction_data, account_metas.clone());
- let message = Message::new(&[instruction], Some(&mint_pubkey));
- let tx = Transaction::new(&[&mint_keypair], message.clone(), bank.last_blockhash());
- let (result, _, logs, _) = process_transaction_and_record_inner(&bank, tx);
- assert!(result.is_err(), "{result:?}");
- let error = format!(
- "Program {invoke_program_id} failed: instruction modified data of an account it does not \
- own"
- );
- assert!(logs.iter().any(|log| log.contains(&error)), "{logs:?}");
- // II. Clone data, call, modifiy in callee and then make the same change in the caller - transaction succeeds
- // Note the caller needs to modify the original account data, not the copy
- let mut account = AccountSharedData::new(42, 10240, &invoke_program_id2);
- let data: Vec<u8> = (0..10240).map(|n| n as u8).collect();
- account.set_data(data);
- bank.store_account(&account_keypair.pubkey(), &account);
- let mut instruction_data = vec![TEST_CALLEE_ACCOUNT_UPDATES, 1, 1];
- instruction_data.extend_from_slice(0usize.to_le_bytes().as_ref());
- instruction_data.extend_from_slice(0usize.to_le_bytes().as_ref());
- instruction_data.extend_from_slice(8190usize.to_le_bytes().as_ref());
- // instruction data for inner CPI
- instruction_data.extend_from_slice(&[TEST_CALLEE_ACCOUNT_UPDATES, 0, 0]);
- instruction_data.extend_from_slice(0usize.to_le_bytes().as_ref());
- instruction_data.extend_from_slice(0usize.to_le_bytes().as_ref());
- instruction_data.extend_from_slice(8190usize.to_le_bytes().as_ref());
- let instruction =
- Instruction::new_with_bytes(invoke_program_id, &instruction_data, account_metas.clone());
- let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
- // works because the account is exactly the same in caller as callee
- assert!(result.is_ok(), "{result:?}");
- }
- #[test]
- fn test_stack_heap_zeroed() {
- agave_logger::setup();
- let GenesisConfigInfo {
- genesis_config,
- mint_keypair,
- ..
- } = create_genesis_config(100_123_456_789);
- let bank = Bank::new_for_tests(&genesis_config);
- let (bank, bank_forks) = bank.wrap_with_bank_forks_for_tests();
- let mut bank_client = BankClient::new_shared(bank);
- let authority_keypair = Keypair::new();
- let (bank, invoke_program_id) = load_program_of_loader_v4(
- &mut bank_client,
- &bank_forks,
- &mint_keypair,
- &authority_keypair,
- "solana_sbf_rust_invoke",
- );
- let account_keypair = Keypair::new();
- let mint_pubkey = mint_keypair.pubkey();
- let account_metas = vec![
- AccountMeta::new(mint_pubkey, true),
- AccountMeta::new(account_keypair.pubkey(), false),
- AccountMeta::new_readonly(invoke_program_id, false),
- ];
- // Check multiple heap sizes. It's generally a good idea, and also it's needed to ensure that
- // pooled heap and stack values are reused - and therefore zeroed - across executions.
- for heap_len in [32usize * 1024, 64 * 1024, 128 * 1024, 256 * 1024] {
- // TEST_STACK_HEAP_ZEROED will recursively check that stack and heap are zeroed until it
- // reaches max CPI invoke depth. We make it fail at max depth so we're sure that there's no
- // legit way to access non-zeroed stack and heap regions.
- let mut instruction_data = vec![TEST_STACK_HEAP_ZEROED];
- instruction_data.extend_from_slice(&heap_len.to_le_bytes());
- let instruction = Instruction::new_with_bytes(
- invoke_program_id,
- &instruction_data,
- account_metas.clone(),
- );
- let message = Message::new(
- &[
- ComputeBudgetInstruction::set_compute_unit_limit(1_400_000),
- ComputeBudgetInstruction::request_heap_frame(heap_len as u32),
- instruction,
- ],
- Some(&mint_pubkey),
- );
- let tx = Transaction::new(&[&mint_keypair], message.clone(), bank.last_blockhash());
- let (result, _, logs, _) = process_transaction_and_record_inner(&bank, tx);
- assert!(result.is_err(), "{result:?}");
- assert!(
- logs.iter()
- .any(|log| log.contains("Cross-program invocation call depth too deep")),
- "{logs:?}"
- );
- }
- }
- #[test]
- fn test_function_call_args() {
- // This function tests edge compiler edge cases when calling functions with more than five
- // arguments and passing by value arguments with more than 16 bytes.
- agave_logger::setup();
- let GenesisConfigInfo {
- genesis_config,
- mint_keypair,
- ..
- } = create_genesis_config(100_123_456_789);
- let (bank, bank_forks) = Bank::new_with_bank_forks_for_tests(&genesis_config);
- let mut bank_client = BankClient::new_shared(bank);
- let authority_keypair = Keypair::new();
- let (bank, program_id) = load_program_of_loader_v4(
- &mut bank_client,
- &bank_forks,
- &mint_keypair,
- &authority_keypair,
- "solana_sbf_rust_call_args",
- );
- #[derive(BorshSerialize, BorshDeserialize, PartialEq, Eq, Debug)]
- struct Test128 {
- a: u128,
- b: u128,
- }
- #[derive(BorshSerialize)]
- struct InputData {
- test_128: Test128,
- arg1: i64,
- arg2: i64,
- arg3: i64,
- arg4: i64,
- arg5: i64,
- arg6: i64,
- arg7: i64,
- arg8: i64,
- }
- #[derive(BorshDeserialize)]
- struct OutputData {
- res_128: u128,
- res_256: Test128,
- many_args_1: i64,
- many_args_2: i64,
- }
- let input_data = InputData {
- test_128: Test128 {
- a: rand::random::<u128>(),
- b: rand::random::<u128>(),
- },
- arg1: rand::random::<i64>(),
- arg2: rand::random::<i64>(),
- arg3: rand::random::<i64>(),
- arg4: rand::random::<i64>(),
- arg5: rand::random::<i64>(),
- arg6: rand::random::<i64>(),
- arg7: rand::random::<i64>(),
- arg8: rand::random::<i64>(),
- };
- let instruction_data = to_vec(&input_data).unwrap();
- let account_metas = vec![
- AccountMeta::new(mint_keypair.pubkey(), true),
- AccountMeta::new(Keypair::new().pubkey(), false),
- ];
- let instruction = Instruction::new_with_bytes(program_id, &instruction_data, account_metas);
- let message = Message::new(&[instruction], Some(&mint_keypair.pubkey()));
- let tx = Transaction::new(&[&mint_keypair], message.clone(), bank.last_blockhash());
- let txs = vec![tx];
- let tx_batch = bank.prepare_batch_for_tests(txs);
- let result = bank
- .load_execute_and_commit_transactions(
- &tx_batch,
- MAX_PROCESSING_AGE,
- ExecutionRecordingConfig {
- enable_cpi_recording: false,
- enable_log_recording: false,
- enable_return_data_recording: true,
- enable_transaction_balance_recording: false,
- },
- &mut ExecuteTimings::default(),
- None,
- )
- .0;
- fn verify_many_args(input: &InputData) -> i64 {
- let a = input
- .arg1
- .overflowing_add(input.arg2)
- .0
- .overflowing_sub(input.arg3)
- .0
- .overflowing_add(input.arg4)
- .0
- .overflowing_sub(input.arg5)
- .0;
- (a % input.arg6)
- .overflowing_sub(input.arg7)
- .0
- .overflowing_add(input.arg8)
- .0
- }
- let return_data = &result[0]
- .as_ref()
- .unwrap()
- .return_data
- .as_ref()
- .unwrap()
- .data;
- let decoded: OutputData = from_slice::<OutputData>(return_data).unwrap();
- assert_eq!(
- decoded.res_128,
- input_data.test_128.a % input_data.test_128.b
- );
- assert_eq!(
- decoded.res_256,
- Test128 {
- a: input_data
- .test_128
- .a
- .overflowing_add(input_data.test_128.b)
- .0,
- b: input_data
- .test_128
- .a
- .overflowing_sub(input_data.test_128.b)
- .0
- }
- );
- assert_eq!(decoded.many_args_1, verify_many_args(&input_data));
- assert_eq!(decoded.many_args_2, verify_many_args(&input_data));
- }
- #[test]
- #[cfg(feature = "sbf_rust")]
- fn test_mem_syscalls_overlap_account_begin_or_end() {
- agave_logger::setup();
- for stricter_abi_and_runtime_constraints in [false, true] {
- let GenesisConfigInfo {
- genesis_config,
- mint_keypair,
- ..
- } = create_genesis_config(100_123_456_789);
- let mut bank = Bank::new_for_tests(&genesis_config);
- let mut feature_set = FeatureSet::all_enabled();
- if !stricter_abi_and_runtime_constraints {
- feature_set.deactivate(&feature_set::stricter_abi_and_runtime_constraints::id());
- feature_set.deactivate(&feature_set::account_data_direct_mapping::id());
- }
- let account_keypair = Keypair::new();
- bank.feature_set = Arc::new(feature_set);
- let (bank, bank_forks) = bank.wrap_with_bank_forks_for_tests();
- let mut bank_client = BankClient::new_shared(bank);
- let authority_keypair = Keypair::new();
- let (bank, loader_v4_program_id) = load_program_of_loader_v4(
- &mut bank_client,
- &bank_forks,
- &mint_keypair,
- &authority_keypair,
- "solana_sbf_rust_account_mem",
- );
- let deprecated_program_id = create_program(
- &bank,
- &bpf_loader_deprecated::id(),
- "solana_sbf_rust_account_mem_deprecated",
- );
- let mint_pubkey = mint_keypair.pubkey();
- for deprecated in [false, true] {
- let program_id = if deprecated {
- deprecated_program_id
- } else {
- loader_v4_program_id
- };
- let account_metas = vec![
- AccountMeta::new(mint_pubkey, true),
- AccountMeta::new_readonly(program_id, false),
- AccountMeta::new(account_keypair.pubkey(), false),
- ];
- let account = AccountSharedData::new(42, 1024, &program_id);
- bank.store_account(&account_keypair.pubkey(), &account);
- for instr in 0..=15 {
- println!(
- "Testing deprecated:{deprecated} \
- stricter_abi_and_runtime_constraints:{stricter_abi_and_runtime_constraints} \
- instruction:{instr}"
- );
- let instruction =
- Instruction::new_with_bytes(program_id, &[instr], account_metas.clone());
- let message = Message::new(&[instruction], Some(&mint_pubkey));
- let tx = Transaction::new(&[&mint_keypair], message.clone(), bank.last_blockhash());
- let (result, _, logs, _) = process_transaction_and_record_inner(&bank, tx);
- let last_line = logs.last().unwrap();
- if stricter_abi_and_runtime_constraints {
- assert!(last_line.contains(" failed: Access violation"), "{logs:?}");
- } else {
- assert!(result.is_ok(), "{logs:?}");
- }
- }
- let account = AccountSharedData::new(42, 0, &program_id);
- bank.store_account(&account_keypair.pubkey(), &account);
- for instr in 0..=15 {
- println!(
- "Testing deprecated:{deprecated} \
- stricter_abi_and_runtime_constraints:{stricter_abi_and_runtime_constraints} \
- instruction:{instr} zero-length account"
- );
- let instruction =
- Instruction::new_with_bytes(program_id, &[instr, 0], account_metas.clone());
- let message = Message::new(&[instruction], Some(&mint_pubkey));
- let tx = Transaction::new(&[&mint_keypair], message.clone(), bank.last_blockhash());
- let (result, _, logs, _) = process_transaction_and_record_inner(&bank, tx);
- let last_line = logs.last().unwrap();
- if stricter_abi_and_runtime_constraints && (!deprecated || instr < 8) {
- assert!(
- last_line.contains(" failed: account data too small")
- || last_line.contains(" failed: Failed to reallocate account data")
- || last_line.contains(" failed: Access violation"),
- "{logs:?}",
- );
- } else {
- // stricter_abi_and_runtime_constraints && deprecated && instr >= 8 succeeds with zero-length accounts
- // because there is no MemoryRegion for the account,
- // so there can be no error when leaving that non-existent region.
- assert!(result.is_ok(), "{logs:?}");
- }
- }
- }
- }
- }
|