状态机(State Machine)是一种常见的设计模式,特别适合用于管理智能合约中的复杂状态转换。使用枚举(Enum)配合状态机模式,可以让合约的状态管理更加清晰、安全和可维护。
状态机是一个由状态和转换组成的系统:
在智能合约中,状态机可以确保:
pragma solidity ^0.8.0;
contract SimpleStateMachine {
enum State { Created, Started, Paused, Completed }
State public currentState;
event StateChanged(State indexed oldState, State indexed newState);
constructor() {
currentState = State.Created;
}
// 状态转换:Created -> Started
function start() public {
require(currentState == State.Created, "Can only start from Created");
State oldState = currentState;
currentState = State.Started;
emit StateChanged(oldState, currentState);
}
// 状态转换:Started -> Paused
function pause() public {
require(currentState == State.Started, "Can only pause when Started");
State oldState = currentState;
currentState = State.Paused;
emit StateChanged(oldState, currentState);
}
// 状态转换:Paused -> Started
function resume() public {
require(currentState == State.Paused, "Can only resume when Paused");
State oldState = currentState;
currentState = State.Started;
emit StateChanged(oldState, currentState);
}
// 状态转换:Started/Paused -> Completed
function complete() public {
require(
currentState == State.Started || currentState == State.Paused,
"Invalid state to complete"
);
State oldState = currentState;
currentState = State.Completed;
emit StateChanged(oldState, currentState);
}
}
投票系统需要管理提案的多个状态,确保投票流程的严格执行:
pragma solidity ^0.8.0;
contract VotingSystem {
enum VoteOption { Abstain, Yes, No }
enum ProposalState { Pending, Active, Passed, Rejected, Executed }
struct Proposal {
string description;
ProposalState state;
uint yesVotes;
uint noVotes;
uint startTime;
uint endTime;
}
mapping(uint => Proposal) public proposals;
mapping(uint => mapping(address => VoteOption)) public votes;
uint public proposalCount;
event ProposalCreated(uint indexed proposalId, string description);
event ProposalStateChanged(uint indexed proposalId, ProposalState newState);
event Voted(uint indexed proposalId, address indexed voter, VoteOption option);
// 创建提案
function createProposal(string memory description, uint duration) public {
uint proposalId = proposalCount++;
proposals[proposalId] = Proposal({
description: description,
state: ProposalState.Pending,
yesVotes: 0,
noVotes: 0,
startTime: block.timestamp,
endTime: block.timestamp + duration
});
emit ProposalCreated(proposalId, description);
}
// 激活提案(状态转换:Pending -> Active)
function activateProposal(uint proposalId) public {
Proposal storage proposal = proposals[proposalId];
require(proposal.state == ProposalState.Pending, "Proposal must be pending");
proposal.state = ProposalState.Active;
emit ProposalStateChanged(proposalId, ProposalState.Active);
}
// 投票(仅在 Active 状态)
function vote(uint proposalId, VoteOption option) public {
Proposal storage proposal = proposals[proposalId];
require(proposal.state == ProposalState.Active, "Proposal not active");
require(block.timestamp < proposal.endTime, "Voting period ended");
require(votes[proposalId][msg.sender] == VoteOption.Abstain, "Already voted");
votes[proposalId][msg.sender] = option;
if (option == VoteOption.Yes) {
proposal.yesVotes++;
} else if (option == VoteOption.No) {
proposal.noVotes++;
}
emit Voted(proposalId, msg.sender, option);
}
// 结束投票(状态转换:Active -> Passed/Rejected)
function finalizeProposal(uint proposalId) public {
Proposal storage proposal = proposals[proposalId];
require(proposal.state == ProposalState.Active, "Proposal not active");
require(block.timestamp >= proposal.endTime, "Voting period not ended");
if (proposal.yesVotes > proposal.noVotes) {
proposal.state = ProposalState.Passed;
} else {
proposal.state = ProposalState.Rejected;
}
emit ProposalStateChanged(proposalId, proposal.state);
}
// 执行提案(状态转换:Passed -> Executed)
function executeProposal(uint proposalId) public {
Proposal storage proposal = proposals[proposalId];
require(proposal.state == ProposalState.Passed, "Proposal must be passed");
// 执行提案逻辑...
proposal.state = ProposalState.Executed;
emit ProposalStateChanged(proposalId, ProposalState.Executed);
}
}
游戏中的角色需要管理多种状态,确保游戏规则的正确执行:
pragma solidity ^0.8.0;
contract GameCharacter {
enum CharacterClass { Warrior, Mage, Archer, Rogue }
enum CharacterState { Idle, Fighting, Resting, Dead }
struct Character {
string name;
CharacterClass class;
CharacterState state;
uint health;
uint level;
}
mapping(address => Character) public characters;
event CharacterCreated(address indexed player, string name, CharacterClass class);
event StateChanged(address indexed player, CharacterState oldState, CharacterState newState);
event HealthChanged(address indexed player, uint newHealth);
// 创建角色
function createCharacter(string memory name, CharacterClass class) public {
require(bytes(characters[msg.sender].name).length == 0, "Character already exists");
characters[msg.sender] = Character({
name: name,
class: class,
state: CharacterState.Idle,
health: 100,
level: 1
});
emit CharacterCreated(msg.sender, name, class);
}
// 开始战斗(状态转换:Idle -> Fighting)
function startBattle() public {
Character storage char = characters[msg.sender];
require(bytes(char.name).length > 0, "Character does not exist");
require(char.state == CharacterState.Idle, "Must be idle to start battle");
require(char.health > 0, "Character is dead");
CharacterState oldState = char.state;
char.state = CharacterState.Fighting;
emit StateChanged(msg.sender, oldState, CharacterState.Fighting);
}
// 结束战斗(状态转换:Fighting -> Idle/Dead)
function endBattle(uint damage) public {
Character storage char = characters[msg.sender];
require(char.state == CharacterState.Fighting, "Not in battle");
CharacterState oldState = char.state;
if (damage >= char.health) {
char.health = 0;
char.state = CharacterState.Dead;
} else {
char.health -= damage;
char.state = CharacterState.Idle;
}
emit HealthChanged(msg.sender, char.health);
emit StateChanged(msg.sender, oldState, char.state);
}
// 休息恢复(状态转换:Idle -> Resting -> Idle)
function rest() public {
Character storage char = characters[msg.sender];
require(char.state == CharacterState.Idle, "Must be idle to rest");
CharacterState oldState = char.state;
char.state = CharacterState.Resting;
emit StateChanged(msg.sender, oldState, CharacterState.Resting);
// 恢复生命值
if (char.health < 100) {
char.health = 100;
emit HealthChanged(msg.sender, char.health);
}
// 休息完成,回到 Idle
char.state = CharacterState.Idle;
emit StateChanged(msg.sender, CharacterState.Resting, CharacterState.Idle);
}
// 获取角色类型说明
function getClassDescription(CharacterClass class) public pure returns (string memory) {
if (class == CharacterClass.Warrior) {
return "Strong melee fighter";
} else if (class == CharacterClass.Mage) {
return "Powerful magic user";
} else if (class == CharacterClass.Archer) {
return "Skilled ranged attacker";
} else {
return "Stealthy assassin";
}
}
}
托管合约需要严格管理交易状态,确保资金安全:
pragma solidity ^0.8.0;
contract Escrow {
enum EscrowState {
Created, // 创建
FundsDeposited, // 资金已存入
InDispute, // 争议中
Completed, // 完成
Refunded, // 已退款
Cancelled // 已取消
}
struct EscrowTransaction {
address buyer;
address seller;
uint amount;
EscrowState state;
}
mapping(uint => EscrowTransaction) public transactions;
uint public transactionCount;
event EscrowCreated(uint indexed txId, address indexed buyer, address indexed seller, uint amount);
event StateChanged(uint indexed txId, EscrowState oldState, EscrowState newState);
// 创建托管交易(状态:Created -> FundsDeposited)
function createEscrow(address seller) public payable returns (uint) {
require(msg.value > 0, "Must send funds");
uint txId = transactionCount++;
transactions[txId] = EscrowTransaction({
buyer: msg.sender,
seller: seller,
amount: msg.value,
state: EscrowState.FundsDeposited
});
emit EscrowCreated(txId, msg.sender, seller, msg.value);
emit StateChanged(txId, EscrowState.Created, EscrowState.FundsDeposited);
return txId;
}
// 完成交易(状态转换:FundsDeposited -> Completed)
function completeEscrow(uint txId) public {
EscrowTransaction storage txn = transactions[txId];
require(msg.sender == txn.buyer, "Only buyer can complete");
require(txn.state == EscrowState.FundsDeposited, "Invalid state");
EscrowState oldState = txn.state;
txn.state = EscrowState.Completed;
payable(txn.seller).transfer(txn.amount);
emit StateChanged(txId, oldState, EscrowState.Completed);
}
// 发起争议(状态转换:FundsDeposited -> InDispute)
function raiseDispute(uint txId) public {
EscrowTransaction storage txn = transactions[txId];
require(
msg.sender == txn.buyer || msg.sender == txn.seller,
"Not authorized"
);
require(txn.state == EscrowState.FundsDeposited, "Invalid state");
EscrowState oldState = txn.state;
txn.state = EscrowState.InDispute;
emit StateChanged(txId, oldState, EscrowState.InDispute);
}
// 退款给买家(状态转换:FundsDeposited/InDispute -> Refunded)
function refund(uint txId) public {
EscrowTransaction storage txn = transactions[txId];
require(msg.sender == txn.seller, "Only seller can refund");
require(
txn.state == EscrowState.FundsDeposited ||
txn.state == EscrowState.InDispute,
"Invalid state"
);
EscrowState oldState = txn.state;
txn.state = EscrowState.Refunded;
payable(txn.buyer).transfer(txn.amount);
emit StateChanged(txId, oldState, EscrowState.Refunded);
}
}
contract StateMachineWithModifiers {
enum State { Created, Active, Paused, Completed }
State public state;
modifier inState(State _state) {
require(state == _state, "Invalid state");
_;
}
modifier transitionTo(State _newState) {
_;
state = _newState;
}
function activate() public inState(State.Created) transitionTo(State.Active) {
// 激活逻辑
}
function pause() public inState(State.Active) transitionTo(State.Paused) {
// 暂停逻辑
}
}
在设计复杂状态机时,建议先绘制状态转换图:
stateDiagram-v2
[*] --> Created
Created --> Active: activate()
Active --> Paused: pause()
Paused --> Active: resume()
Active --> Completed: complete()
Paused --> Completed: complete()
Completed --> [*]
或者使用流程图形式:
graph LR
Created -->|activate| Active
Active -->|pause| Paused
Paused -->|resume| Active
Active -->|complete| Completed
Paused -->|complete| Completed
style Created fill:#e1f5ff
style Active fill:#90ee90
style Paused fill:#ffeb3b
style Completed fill:#9e9e9e
event StateChanged(
uint indexed entityId,
State indexed oldState,
State indexed newState,
uint timestamp,
address actor
);
function changeState(uint entityId, State newState) internal {
State oldState = entities[entityId].state;
entities[entityId].state = newState;
emit StateChanged(
entityId,
oldState,
newState,
block.timestamp,
msg.sender
);
}
function canTransition(State from, State to) internal pure returns (bool) {
// 定义允许的状态转换
if (from == State.Created && to == State.Active) return true;
if (from == State.Active && to == State.Paused) return true;
if (from == State.Paused && to == State.Active) return true;
if ((from == State.Active || from == State.Paused) && to == State.Completed) return true;
return false;
}
function setState(State newState) internal {
require(canTransition(state, newState), "Invalid state transition");
state = newState;
}
状态机模式是智能合约开发中的重要设计模式:
在设计复杂业务逻辑时,优先考虑使用状态机模式,它能让合约更加健壮和易于理解。