Grunderna i Web3- och DApp-utveckling · Lektion

Lagringsoptimering

Packing och slots

Lektion 2 av 413 steg

Lagringsoptimering är en gratis lektion i Grunderna i Web3- och DApp-utveckling på CoddyKit. Detta är lektion 2 av 4. Du kan läsa vilka 3 lektioner som helst i den här lärvägen kostnadsfritt i sin helhet – därefter låser CoddyKit PRO upp alla lektioner, plus praktisk övning med en inbyggd kodredigerare och en AI-lärare dygnet runt. Den ingår i lärvägen för Grunderna i Web3- och DApp-utveckling, och Era framsteg synkroniseras mellan webben och CoddyKit-appen. Kursen i Grunderna i Web3- och DApp-utveckling innehåller totalt 4 lektioner.

Grunderna i storage-slots

Kontraktets storage är en gigantisk array med 32-byte-slots, indexerad från slot 0. Tillståndsvariabler tilldelas slots i deklarationsordning.

Varje slot Ni skriver till kostar gas, så ju färre slots Era data upptar, desto billigare blir kontraktet att använda. Att förstå slot-layouten är grunden för att optimera storage.

contract Layout {
    uint256 a; // slot 0
    uint256 b; // slot 1
    uint256 c; // slot 2
}

Packning av variabler

Solidity-kompilatorn packar flera små variabler i en enda 32-byte-slot när de får plats efter varandra.

En uint128 använder 16 byte, så två sådana delar på en slot. En bool använder 1 byte och en uint8 använder 1 byte. Packning minskar både kostnaderna för distribution och för storage vid körning.

contract Packed {
    uint128 a; // slot 0 (bytes 0-15)
    uint128 b; // slot 0 (bytes 16-31)
    uint256 c; // slot 1
}

Deklarationsordningen spelar roll

Packning fungerar bara för variabler som är intill varandra i deklarationen. En dåligt ordnad layout slösar slots.

I det dåliga exemplet nedan tvingar uint256 de två uint128-variablerna till separata slots. Om Ni ordnar om dem så att de små typerna ligger tillsammans kan de packas.

// BAD: 3 slots
uint128 a; // slot 0
uint256 b; // slot 1
uint128 c; // slot 2

// GOOD: 2 slots
uint128 a; // slot 0
uint128 c; // slot 0
uint256 b; // slot 1

Välja heltalsstorlekar

Mindre heltal sparar bara gas när de packas. En ensam uint8 i sin egen slot är inte billigare än en uint256 och kan till och med kosta mer på grund av maskningsoperationer.

Tumregel: använd uint256 som standard och minska storleken endast när flera små värden får plats i en slot.

Packa structs

Structs följer samma packningsregler. Ordna struct-medlemmarna så att små typer grupperas tillsammans. En välpackad struct kan minska antalet SSTORE-operationer avsevärt.

struct Order {
    uint128 amount;  // slot 0
    uint64 timestamp;// slot 0
    uint64 id;       // slot 0
    address maker;   // slot 1
}

Konstanter och immutables

Värden som aldrig ändras bör inte lagras i storage över huvud taget.

  • constant — bäddas in i bytekoden vid kompilering, ingen storage
  • immutable — sätts en gång i konstruktorn och lagras i bytekoden, inte i storage

Båda undviker helt dyra SLOAD-operationer.

uint256 public constant MAX_SUPPLY = 10000;
address public immutable owner;

constructor() {
    owner = msg.sender;
}

Mappings och dynamiska arrayer

Mappings och dynamiska arrayer packas inte. Varje post upptar sin egen slot, som beräknas genom att nyckeln hashas tillsammans med bassloten.

Ni kan inte packa över flera mapping-poster, men Ni kan packa den struct som lagras som mapping-värde. Om värdestructen utformas så att den ryms i färre slots sparar det gas vid varje skrivning.

mapping(address => Order) public orders;
// each Order packs into 2 slots regardless of mapping

Cacha storage-läsningar

Om Ni läser en storage-variabel upprepade gånger i en funktion betalar Ni för varje åtkomst. Kopiera den till en lokal memory-variabel en gång och använd sedan den lokala variabeln.

Detta är särskilt värdefullt i loopar, där varje iteration annars skulle läsa från storage på nytt.

uint256 len = items.length; // cache length once
for (uint256 i = 0; i < len; i++) {
    // process items[i]
}

Samlade skrivningar

När Ni uppdaterar flera fält i en packad struct ska Ni läsa in structen i memory, ändra den och sedan skriva tillbaka den en gång. Kompilatorn kan slå ihop intilliggande fält till en enda SSTORE.

Om Ni skriver fälten ett i taget kan det utlösa flera läs-ändra-skriv-cykler på samma slot.

Order memory o = orders[id];
o.amount = newAmount;
o.timestamp = uint64(block.timestamp);
orders[id] = o; // single packed write of slot 0

Kostnaden från noll till icke-noll

Att initiera en slot från noll till ett värde som inte är noll kostar 20000 gas, medan en uppdatering av en slot som redan har ett värde som inte är noll bara kostar 5000 gas.

Därför förvärmer vissa kontrakt slots eller använder ett sentinel-värde (till exempel 1 i stället för 0) för att hålla slots icke-noll, vilket innebär en engångskostnad i utbyte mot billigare upprepade uppdateringar.

// Using 1 as 'false' and 2 as 'true' keeps the slot non-zero
uint256 private locked = 1; // never goes back to 0

Checklista för layoutgranskning

När Ni granskar storage med avseende på gas:

  • Gruppera små typer så att de packas i gemensamma slots
  • Använd constant / immutable för fasta värden
  • Cacha upprepade storage-läsningar i memory
  • Samla struct-skrivningar
  • Undvik onödiga övergångar från noll till icke-noll

Verifiera alltid ändringarna med en gasrapport.

Snabbtest

Ni deklarerar en uint128, sedan en uint256 och därefter ytterligare en uint128. Hur många storage-slots använder de?

Repetition

Ni har lärt Er att optimera storage-layout:

  • Storage består av 32-byte-slots; intilliggande små typer packas tillsammans
  • Deklarationsordningen avgör packningen
  • constant och immutable undviker storage helt
  • Cacha läsningar och samla struct-skrivningar
  • Ta hänsyn till kostnaden för skrivningar från noll till icke-noll

Härnäst tittar vi på hur loopar och calldata kan optimeras.

Gratis att börja

Lär dig Grunderna i Web3- och DApp-utveckling med en AI-lärare – gratis

Skriv och kör riktig kod i webbläsaren, få omedelbar hjälp av en AI-lärare dygnet runt och fortsätt där du slutade – på webben eller i appen.

Kurser
29
Lektioner
105

Vanliga frågor

Är lektionen ”Lagringsoptimering” gratis?

Ja – du kan läsa vilka 3 lektioner som helst i lärvägen Grunderna i Web3- och DApp-utveckling, inklusive ”Lagringsoptimering”, kostnadsfritt i sin helhet här på webben. Därefter låser CoddyKit PRO upp alla lektioner, plus interaktiv övning med en inbyggd kodredigerare och en AI-lärare dygnet runt. Kursen i Grunderna i Web3- och DApp-utveckling innehåller totalt 4 lektioner.

Vad lär jag mig i ”Lagringsoptimering”?

Packing och slots Ni övar på Grunderna i Web3- och DApp-utveckling med praktisk kod som körs direkt i webbläsaren, medan en AI-handledare som är tillgänglig dygnet runt svarar på Era frågor under lektionen.

Behöver jag någon erfarenhet för att börja lära mig Grunderna i Web3- och DApp-utveckling?

Du behöver inga förkunskaper. Utbildningen i Grunderna i Web3- och DApp-utveckling på CoddyKit är upplagd för allt från nybörjare till avancerade elever, så att du kan börja här eller från början och gå fram i din egen takt. Detta är lektion 2 av 4.

Hur lång tid tar lektionen ”Lagringsoptimering”?

De flesta CoddyKit-lektioner tar cirka 5–10 minuter. Varje lektion är kort och interaktiv, så att du gör stadiga framsteg och kan fortsätta precis där du slutade – på webben eller i appen.

Kan jag skriva och köra kod i den här Grunderna i Web3- och DApp-utveckling-lektionen?

Ja. Varje Grunderna i Web3- och DApp-utveckling-lektion innehåller en inbyggd kodredigerare, så att du kan skriva och köra riktig kod direkt i webbläsaren och få omedelbar AI-feedback – utan lokal installation.

Alla lektioner i den här kursen

  1. Modell för gaskostnader
  2. Lagringsoptimering
  3. Loop- och calldata-trick
  4. Mäta gas
← Tillbaka till Grunderna i Web3- och DApp-utveckling