-
Notifications
You must be signed in to change notification settings - Fork 710
Increase Stylus smart contract size limit via merge-on-activate #4193
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
a1c8594
bc11859
6b48d04
15bbdc9
e371f38
fdb0be2
b4a6488
60f4479
4e989f2
de08187
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -113,7 +113,7 @@ func (p Programs) ActivateProgram(evm *vm.EVM, address common.Address, runCtx *c | |
| // already activated and up to date | ||
| return 0, codeHash, common.Hash{}, nil, false, ProgramUpToDateError() | ||
| } | ||
| wasm, err := getWasm(statedb, address, params.MaxWasmSize) | ||
| wasm, err := getWasm(statedb, address, params) | ||
| if err != nil { | ||
| return 0, codeHash, common.Hash{}, nil, false, err | ||
| } | ||
|
|
@@ -224,7 +224,7 @@ func (p Programs) CallProgram( | |
| statedb.AddStylusPages(program.footprint) | ||
| defer statedb.SetStylusPagesOpen(open) | ||
|
|
||
| localAsm := handleProgramPrepare(statedb, moduleHash, contract.Address(), contract.Code, contract.CodeHash, params.MaxWasmSize, params.PageLimit, evm.Context.Time, debugMode, program, runCtx) | ||
| localAsm := handleProgramPrepare(statedb, moduleHash, contract.Address(), contract.Code, contract.CodeHash, params, evm.Context.Time, debugMode, program, runCtx) | ||
|
|
||
| evmData := &EvmData{ | ||
| arbosVersion: evm.Context.ArbOSVersion, | ||
|
|
@@ -298,30 +298,104 @@ func evmMemoryCost(size uint64) uint64 { | |
| return linearCost + squareCost | ||
| } | ||
|
|
||
| func getWasm(statedb vm.StateDB, program common.Address, maxWasmSize uint32) ([]byte, error) { | ||
| func getWasm(statedb vm.StateDB, program common.Address, params *StylusParams) ([]byte, error) { | ||
| prefixedWasm := statedb.GetCode(program) | ||
| return getWasmFromContractCode(prefixedWasm, maxWasmSize) | ||
| return getWasmFromContractCode(statedb, prefixedWasm, params, true) | ||
| } | ||
|
|
||
| func getWasmFromContractCode(prefixedWasm []byte, maxWasmSize uint32) ([]byte, error) { | ||
| if prefixedWasm == nil { | ||
| func getWasmFromContractCode(statedb vm.StateDB, prefixedWasm []byte, params *StylusParams, isActivation bool) ([]byte, error) { | ||
| if len(prefixedWasm) == 0 { | ||
pmikolajczyk41 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| return nil, ProgramNotWasmError() | ||
| } | ||
| wasm, dictByte, err := state.StripStylusPrefix(prefixedWasm) | ||
|
|
||
| if state.IsStylusClassicProgramPrefix(prefixedWasm) { | ||
| return handleClassicStylus(prefixedWasm, params.MaxWasmSize) | ||
| } | ||
|
|
||
| if params.arbosVersion >= gethParams.ArbosVersion_StylusContractLimit { | ||
| if state.IsStylusRootProgramPrefix(prefixedWasm) { | ||
| return handleRootStylus(statedb, prefixedWasm, params.MaxWasmSize, params.MaxFragmentCount, isActivation) | ||
| } | ||
|
|
||
| if state.IsStylusFragmentPrefix(prefixedWasm) { | ||
| return nil, errors.New("fragmented stylus programs cannot be activated directly; activate the root program instead") | ||
| } | ||
| } | ||
|
|
||
| return nil, ProgramNotWasmError() | ||
| } | ||
|
|
||
| func handleClassicStylus(data []byte, maxSize uint32) ([]byte, error) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's a style question, but I don't like this function name. It's visible/theoretically callable from the entire module and "handle" doesn't mean anything for that context. Suggest something like "getWasmFromClassicStylus" or something similar. |
||
| wasm, dictByte, err := state.StripStylusPrefix(data) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
|
|
||
| dict, err := getStylusCompressionDict(dictByte) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
|
|
||
| return arbcompress.DecompressWithDictionary(wasm, int(maxSize), dict) | ||
| } | ||
|
|
||
| func handleRootStylus(statedb vm.StateDB, data []byte, maxSize uint32, maxFragments uint16, isActivation bool) ([]byte, error) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same |
||
| root, err := state.NewStylusRoot(data) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
|
|
||
| if isActivation { | ||
| if root.DecompressedLength > maxSize { | ||
| return nil, fmt.Errorf("invalid wasm: decompressedLength %d is greater then MaxWasmSize %d", root.DecompressedLength, maxSize) | ||
| } | ||
| if len(root.Addresses) > int(maxFragments) { | ||
| return nil, fmt.Errorf("invalid wasm: fragment count exceeds limit of %d", maxFragments) | ||
| } | ||
| } | ||
|
|
||
| if len(root.Addresses) == 0 { | ||
| return nil, fmt.Errorf("invalid wasm: fragment count cannot be zero") | ||
| } | ||
|
|
||
| var compressedWasm []byte | ||
| for _, addr := range root.Addresses { | ||
| fragCode := statedb.GetCode(addr) | ||
|
|
||
| payload, err := state.StripStylusFragmentPrefix(fragCode) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
|
|
||
| compressedWasm = append(compressedWasm, payload...) | ||
| } | ||
|
|
||
| dict, err := getStylusCompressionDict(root.DictionaryType) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
|
|
||
| var dict arbcompress.Dictionary | ||
| switch dictByte { | ||
| wasm, err := arbcompress.DecompressWithDictionary(compressedWasm, int(root.DecompressedLength), dict) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
|
|
||
| if len(wasm) != int(root.DecompressedLength) { | ||
| return nil, fmt.Errorf("invalid wasm: decompressed length %d does not match expected length %d", len(wasm), root.DecompressedLength) | ||
| } | ||
|
|
||
| return wasm, nil | ||
| } | ||
|
|
||
| func getStylusCompressionDict(id byte) (arbcompress.Dictionary, error) { | ||
| switch id { | ||
| case 0: | ||
| dict = arbcompress.EmptyDictionary | ||
| return arbcompress.EmptyDictionary, nil | ||
| case 1: | ||
| dict = arbcompress.StylusProgramDictionary | ||
| return arbcompress.StylusProgramDictionary, nil | ||
| default: | ||
| return nil, fmt.Errorf("unsupported dictionary %v", dictByte) | ||
| return 0, fmt.Errorf("unsupported dictionary type: %d", id) | ||
| } | ||
| return arbcompress.DecompressWithDictionary(wasm, int(maxWasmSize), dict) | ||
| } | ||
|
|
||
| // Gets a program entry, which may be expired or not yet activated. | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| ### Added | ||
| - Increase Stylus smart contract size limit via merge-on-activate |
| +95 −5 | core/state/statedb_arbitrum.go | |
| +1 −1 | core/vm/evm.go | |
| +94 −0 | core/vm/evm_arbitrum_test.go | |
| +1 −1 | core/vm/instructions.go | |
| +73 −0 | core/vm/instructions_test.go | |
| +1 −1 | core/vm/interpreter.go | |
| +1 −0 | params/config_arbitrum.go |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let's use uint8 and only take 1.
255 fragments should be enough, and we're very close to the 32byte limit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok here is the PR for that #4285