question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Improvements to state machines

See original GitHub issue

Overview

Improve the design of Brownie state machines.

This is a work in progress, if you have any ideas feel free to leave them as comments or reach out on Gitter.

Specification

  • Eliminate the need for an __init__ method. Handling this as a classmethod is confusing and unintuitive. Replace it with an optional setup_first classmethod that achieves the same functionality (runs once prior to the snapshot).
  • Eliminate the need for a test that launches the state machine. Convert the state_machine fixture to a decorator which accepts pytest fixtures to be made available in the test.
  • Along with injecting strategies as arguments for rules and invariants, also inject pytest fixtures.

Example

This is a condensed version of the example state machine given in the documentation:

class OldStateMachine:

    value = strategy('uint256', max_value="1 ether")
    address = strategy('address')

    def __init__(cls, accounts, Depositer):
        # deploy the contract at the start of the test
        cls.accounts = accounts
        cls.contract = Depositer.deploy({'from': accounts[0]})

    def setup(self):
        # zero the deposit amounts at the start of each test run
        self.deposits = {i: 0 for i in self.accounts}

    def rule_deposit(self, address, value):
        # make a deposit and adjust the local record
        self.contract.deposit_for(address, {'from': self.accounts[0], 'value': value})
        self.deposits[address] += value

    def invariant(self):
        # compare the contract deposit amounts with the local record
        for address, amount in self.deposits.items():
            assert self.contract.deposited(address) == amount

def test_stateful(Depositer, accounts, state_machine):
    state_machine(OldStateMachine, accounts, Depositer)

Here is the same state machine, rewritten with the proposed new functionality:

@state_machine(Depositor, accounts)
class NewStateMachine:

    value = strategy('uint256', max_value="1 ether")
    address = strategy('address')

    def setup_first(cls, accounts, Depositer):
        # deploy the contract at the start of the test
        cls.contract = Depositer.deploy({'from': accounts[0]})

    def setup(self, accounts):
        # zero the deposit amounts at the start of each test run
        self.deposits = {i: 0 for i in accounts}

    def rule_deposit(self, accounts, address, value):
        # make a deposit and adjust the local record
        self.contract.deposit_for(address, {'from': accounts[0], 'value': value})
        self.deposits[address] += value

    def invariant(self):
        # compare the contract deposit amounts with the local record
        for address, amount in self.deposits.items():
            assert self.contract.deposited(address) == amount

Dependencies

Breaking change. Can happen as a part of v2.0.0. Also, this means plenty of time to bikeshed about the design 😄

Issue Analytics

  • State:open
  • Created 3 years ago
  • Comments:15 (14 by maintainers)

github_iconTop GitHub Comments

1reaction
iamdefinitelyahumancommented, May 18, 2020

Related - it should be possible to selectively disable coverage analysis during a stateful test. Either on a per rule/invariant basis, or a broad “disable during invariants”.

1reaction
fubuloubucommented, May 11, 2020

What about:

  • create_snapshot
  • setup_case
  • teardown_case
  • revert_snapshot

Pros:

  1. Creates a delineation between snapshots (happens once) vs. cases (happens N times)
  2. Doesn’t confuse the purposes of the two functions (one deploys smart contracts, the other deals with internal state)
Read more comments on GitHub >

github_iconTop Results From Across the Web

The Rise Of The State Machines - Smashing Magazine
The UI development became difficult in the last couple of years. That is because we pushed the state management to the browser.
Read more >
Introduction to State Machine and Use Cases
State machines model explicit states to control the transition from one value to another in response to inputs.
Read more >
Why Developers Never Use State Machines - Workflow Engine
At first sight, state machines seem to be an easy tool for developers. Nonetheless, developers soon start to regret using them. Read to...
Read more >
Design state machines for microservices | Red Hat Developer
State machines help engineers visualize a resource's behavior, find gaps or inconsistencies, organize code, and improve test coverage. They also ...
Read more >
Using state machines to define behaviors and state ... - Medium
How do we ensure that we've included all changes? If so how do we program it? What's a state machine? A methodology for...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found