Search code examples
ethereumsmartcontractsvyper

StateAccessViolation: Value must be a literal - Vyper Ethereum smart contract


Version Information

  • vyper Version (output of vyper --version): 0.2.8+commit.069936f
  • OS: osx
  • Python Version (output of python --version): Python 2.7.16
  • Environment (output of pip freeze):
altgraph==0.10.2
bdist-mpkg==0.5.0
bonjour-py==0.3
macholib==1.5.1
matplotlib==1.3.1
modulegraph==0.10.4
numpy==1.8.0rc1
py2app==0.7.3
pyobjc-core==2.5.1
pyobjc-framework-Accounts==2.5.1
pyobjc-framework-AddressBook==2.5.1
pyobjc-framework-AppleScriptKit==2.5.1
pyobjc-framework-AppleScriptObjC==2.5.1
pyobjc-framework-Automator==2.5.1
pyobjc-framework-CFNetwork==2.5.1
pyobjc-framework-Cocoa==2.5.1
pyobjc-framework-Collaboration==2.5.1
pyobjc-framework-CoreData==2.5.1
pyobjc-framework-CoreLocation==2.5.1
pyobjc-framework-CoreText==2.5.1
pyobjc-framework-DictionaryServices==2.5.1
pyobjc-framework-EventKit==2.5.1
pyobjc-framework-ExceptionHandling==2.5.1
pyobjc-framework-FSEvents==2.5.1
pyobjc-framework-InputMethodKit==2.5.1
pyobjc-framework-InstallerPlugins==2.5.1
pyobjc-framework-InstantMessage==2.5.1
pyobjc-framework-LatentSemanticMapping==2.5.1
pyobjc-framework-LaunchServices==2.5.1
pyobjc-framework-Message==2.5.1
pyobjc-framework-OpenDirectory==2.5.1
pyobjc-framework-PreferencePanes==2.5.1
pyobjc-framework-PubSub==2.5.1
pyobjc-framework-QTKit==2.5.1
pyobjc-framework-Quartz==2.5.1
pyobjc-framework-ScreenSaver==2.5.1
pyobjc-framework-ScriptingBridge==2.5.1
pyobjc-framework-SearchKit==2.5.1
pyobjc-framework-ServiceManagement==2.5.1
pyobjc-framework-Social==2.5.1
pyobjc-framework-SyncServices==2.5.1
pyobjc-framework-SystemConfiguration==2.5.1
pyobjc-framework-WebKit==2.5.1
pyOpenSSL==0.13.1
pyparsing==2.0.1
python-dateutil==1.5
pytz==2013.7
scipy==0.13.0b1
six==1.4.1
xattr==0.6.4

this call of a for loop:

for i in range(self.some_uint256):
      # do something...

is throwing the error: StateAccessViolation: Value must be a literal

full error output:

vyper.exceptions.StateAccessViolation: Value must be a literalvyper.exceptions.StateAccessViolation: Value must be a literal
contract "vyper-farm/contracts/Farm.vy", function "_employ", line 152:4
151
---> 152 for i in range(self.num_employees):
-------------^
153 pass

what exactly am i doing wrong?

is this a misunderstanding as to what a literal is on my part?


Solution

  • the issue above is not one of misunderstanding the for loop's use, instead it is a result of incompatible coding style with the security measures of vyper

    the reason the for loop was being created was to make sure when an 'employee' was 'fired' or 'quit' then there wouldn't be an empty record in the list of 'employee's which was being maintained

    instead, in order to avoid using a for loop altogether, and with a small sacrifice of not being able to remove no longer 'active employee's, best practice is to just track the 'employee' in a hashmap:

    idToEmployee: HashMap[uint256, employee]
    

    and when tracking the employees, simply assign an id attribute to the 'employee' using a global variable called num_employees

    ex:

    def employ():
       new_employee: employee = employee ({
            id: self.num_employees
       })
    
       self.idToEmployee[self.num_employees] = new_employee
    
    

    when attempting to view or update that employee's info simply use:

    self.idToEmployee[id]
    

    @vladimir has a good explanation of how range is passed variables if there is still confusion about for loops in vyper for the reader