| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384 |
- #![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::SVMMessage,
- 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,
- },
- };
- #[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() {
- solana_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("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 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();
- // Call user program
- let (_bank, program_id) = load_program_of_loader_v4(
- &mut bank_client,
- &bank_forks,
- &mint_keypair,
- &authority_keypair,
- program.0,
- );
- let account_metas = vec![
- AccountMeta::new(mint_keypair.pubkey(), true),
- AccountMeta::new(Keypair::new().pubkey(), false),
- ];
- let instruction = Instruction::new_with_bytes(program_id, &[1], account_metas);
- let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
- 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() {
- solana_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() {
- solana_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() {
- solana_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() {
- solana_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() {
- solana_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() {
- solana_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 (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),
- ];
- 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,
- );
- // 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),
- &[invoked_program_id.clone()],
- None,
- &bank,
- );
- do_invoke_failure_test_local(
- TEST_PRIVILEGE_ESCALATION_WRITABLE,
- TransactionError::InstructionError(0, InstructionError::PrivilegeEscalation),
- &[invoked_program_id.clone()],
- 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 (129 > 128)"
- ),
- ]),
- &bank,
- );
- do_invoke_failure_test_local(
- TEST_RETURN_ERROR,
- TransactionError::InstructionError(0, InstructionError::Custom(42)),
- &[invoked_program_id.clone()],
- None,
- &bank,
- );
- do_invoke_failure_test_local(
- TEST_PRIVILEGE_DEESCALATION_ESCALATION_SIGNER,
- TransactionError::InstructionError(0, InstructionError::PrivilegeEscalation),
- &[invoked_program_id.clone()],
- None,
- &bank,
- );
- do_invoke_failure_test_local(
- TEST_PRIVILEGE_DEESCALATION_ESCALATION_WRITABLE,
- TransactionError::InstructionError(0, InstructionError::PrivilegeEscalation),
- &[invoked_program_id.clone()],
- None,
- &bank,
- );
- do_invoke_failure_test_local_with_compute_check(
- TEST_WRITABLE_DEESCALATION_WRITABLE,
- TransactionError::InstructionError(0, InstructionError::ReadonlyDataModified),
- &[invoked_program_id.clone()],
- 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),
- &[invoked_program_id.clone()],
- None,
- &bank,
- );
- do_invoke_failure_test_local(
- TEST_DUPLICATE_PRIVILEGE_ESCALATION_WRITABLE,
- TransactionError::InstructionError(0, InstructionError::PrivilegeEscalation),
- &[invoked_program_id.clone()],
- 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() {
- solana_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() {
- solana_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()),
- );
- 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() {
- solana_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() {
- solana_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", 801),
- ("solana_sbf_rust_alloc", 4983),
- ("solana_sbf_rust_custom_heap", 339),
- ("solana_sbf_rust_dep_crate", 22),
- ("solana_sbf_rust_iter", 1414),
- ("solana_sbf_rust_many_args", 1287),
- ("solana_sbf_rust_mem", 1322),
- ("solana_sbf_rust_membuiltins", 329),
- ("solana_sbf_rust_noop", 334),
- ("solana_sbf_rust_param_passing", 109),
- ("solana_sbf_rust_rand", 312),
- ("solana_sbf_rust_sanity", 17902),
- ("solana_sbf_rust_secp256k1_recover", 88670),
- ("solana_sbf_rust_sha", 22175),
- ]);
- }
- 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() {
- solana_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);
- assert!(result.is_err());
- assert_eq!(
- result.unwrap_err().unwrap(),
- TransactionError::InstructionError(0, InstructionError::NotEnoughAccountKeys)
- );
- assert!(bank.get_account(&sysvar::instructions::id()).is_none());
- }
- 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,
- 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.
- solana_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() {
- solana_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() {
- solana_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() {
- solana_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() {
- solana_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;
- solana_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() {
- solana_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() {
- solana_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() {
- solana_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() {
- solana_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() {
- solana_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());
- }
- 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() {
- solana_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() {
- solana_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() {
- solana_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(
- SVMMessage::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(
- SVMMessage::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() {
- solana_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() {
- solana_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());
- }
- 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() {
- solana_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());
- }
- 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() {
- solana_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() {
- solana_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() {
- solana_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() {
- solana_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());
- }
- 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() {
- solana_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());
- }
- 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.
- solana_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());
- }
- 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() {
- solana_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());
- }
- 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() {
- solana_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());
- }
- 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
- solana_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());
- 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() {
- solana_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.
- solana_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() {
- solana_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());
- }
- 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:?}");
- }
- }
- }
- }
- }
|