Skip to content
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

Allow popping of messages at specified indices #23

Merged
merged 2 commits into from
Jan 27, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions src/NFT/AgentCommunication.sol
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,14 @@ contract AgentCommunication is Ownable {
return DoubleEndedStructQueue.at(queues[agentAddress], idx);
}

function popNextMessage(address agentAddress) public returns (DoubleEndedStructQueue.MessageContainer memory) {
function popMessageAtIndex(address agentAddress, uint256 idx)
public
returns (DoubleEndedStructQueue.MessageContainer memory)
{
if (msg.sender != agentAddress) {
revert MessageNotSentByAgent();
}
DoubleEndedStructQueue.MessageContainer memory message = DoubleEndedStructQueue.popFront(queues[agentAddress]);
DoubleEndedStructQueue.MessageContainer memory message = DoubleEndedStructQueue.popAt(queues[agentAddress], idx);
emit LogMessage(message.sender, agentAddress, message.message, message.value);
return message;
}
Expand Down
22 changes: 22 additions & 0 deletions src/NFT/DoubleEndedStructQueue.sol
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,28 @@ library DoubleEndedStructQueue {
}
}

function popAt(Bytes32Deque storage deque, uint256 index) internal returns (MessageContainer memory value) {
if (index >= length(deque)) Panic.panic(Panic.ARRAY_OUT_OF_BOUNDS);
unchecked {
if (index == 0) {
return popFront(deque);
} else if (index == length(deque) - 1) {
return popBack(deque);
} else {
uint128 actualIndex = deque._begin + uint128(index);
value = deque._data[actualIndex];
delete deque._data[actualIndex];

// Shift elements to fill the gap
for (uint128 i = actualIndex; i < deque._end - 1; i++) {
deque._data[i] = deque._data[i + 1];
}
delete deque._data[deque._end - 1];
deque._end--;
}
}
}

function clear(Bytes32Deque storage deque) internal {
deque._begin = 0;
deque._end = 0;
Expand Down
73 changes: 50 additions & 23 deletions test/AgentCommunication.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,15 @@ contract AgentCommunicationTest is Test {
address payable treasury = payable(address(0x789));
uint256 pctToTreasuryInBasisPoints = 7000;

function buildMessage() public view returns (DoubleEndedStructQueue.MessageContainer memory) {
function buildMessage(bytes memory customMessage)
public
view
returns (DoubleEndedStructQueue.MessageContainer memory)
{
return DoubleEndedStructQueue.MessageContainer({
sender: agent,
recipient: address(0x789),
message: "Hello, Agent!",
message: customMessage,
value: 1000000000000000000
});
}
Expand Down Expand Up @@ -56,7 +60,7 @@ contract AgentCommunicationTest is Test {
}

function testSendMessage() public {
DoubleEndedStructQueue.MessageContainer memory message = buildMessage();
DoubleEndedStructQueue.MessageContainer memory message = buildMessage("Hello!");
vm.deal(owner, 1 ether);

// Record initial balances
Expand All @@ -82,7 +86,7 @@ contract AgentCommunicationTest is Test {
}

function testSendMessageInsufficientValue() public {
DoubleEndedStructQueue.MessageContainer memory message = buildMessage();
DoubleEndedStructQueue.MessageContainer memory message = buildMessage("Hello!");
vm.deal(agent, 1 ether);
vm.startPrank(agent);
vm.expectRevert("Insufficient message value");
Expand All @@ -91,7 +95,7 @@ contract AgentCommunicationTest is Test {
}

function testNewMessageSentEvent() public {
DoubleEndedStructQueue.MessageContainer memory message = buildMessage();
DoubleEndedStructQueue.MessageContainer memory message = buildMessage("Hello!");
vm.deal(agent, 1 ether);
vm.startPrank(agent);

Expand All @@ -104,38 +108,61 @@ contract AgentCommunicationTest is Test {
vm.stopPrank();
}

function testPopNextMessage() public {
// Create a message container
DoubleEndedStructQueue.MessageContainer memory message = buildMessage();
function testPopMessage() public {
// Create a message containers
DoubleEndedStructQueue.MessageContainer memory message_1 = buildMessage("Hello 1!");
DoubleEndedStructQueue.MessageContainer memory message_2 = buildMessage("Hello 2!");
DoubleEndedStructQueue.MessageContainer memory message_3 = buildMessage("Hello 3!");
DoubleEndedStructQueue.MessageContainer memory message_4 = buildMessage("Hello 4!");
DoubleEndedStructQueue.MessageContainer memory message_5 = buildMessage("Hello 5!");

// Fund the agent and start the prank
vm.deal(agent, 1 ether);
vm.deal(agent, 5 ether);
vm.startPrank(agent);

// Send the message
agentComm.sendMessage{value: message.value}(message.recipient, message.message);
// Send the messages
agentComm.sendMessage{value: message_1.value}(message_1.recipient, message_1.message);
agentComm.sendMessage{value: message_2.value}(message_2.recipient, message_2.message);
agentComm.sendMessage{value: message_3.value}(message_3.recipient, message_3.message);
agentComm.sendMessage{value: message_4.value}(message_4.recipient, message_4.message);
agentComm.sendMessage{value: message_5.value}(message_5.recipient, message_5.message);
vm.stopPrank();

// Start the prank again for popping the message
vm.startPrank(message.recipient);
vm.startPrank(message_1.recipient);

// Expect the LogMessage event to be emitted when popping the message
vm.expectEmit(true, true, true, true);
emit AgentCommunication.LogMessage(message.sender, message.recipient, message.message, message.value);
emit AgentCommunication.LogMessage(message_1.sender, message_1.recipient, message_1.message, message_1.value);

// Pop the next message
DoubleEndedStructQueue.MessageContainer memory poppedMessage = agentComm.popNextMessage(message.recipient);
DoubleEndedStructQueue.MessageContainer memory poppedMessage_1 =
agentComm.popMessageAtIndex(message_1.recipient, 0);
vm.stopPrank();

// Assert that the popped message matches the original message
assertEq(poppedMessage_1.sender, message_1.sender);
assertEq(poppedMessage_1.recipient, message_1.recipient);
assertEq(poppedMessage_1.message, message_1.message);
assertEq(poppedMessage_1.value, message_1.value);

// Start the prank again for popping another message
vm.startPrank(message_1.recipient);

// Pop the message at specified index
DoubleEndedStructQueue.MessageContainer memory poppedMessage_2 =
agentComm.popMessageAtIndex(message_1.recipient, 2);
vm.stopPrank();

// Assert that the popped message matches the original message
assertEq(poppedMessage.sender, message.sender);
assertEq(poppedMessage.recipient, message.recipient);
assertEq(poppedMessage.message, message.message);
assertEq(poppedMessage.value, message.value);
assertEq(poppedMessage_2.sender, message_4.sender);
assertEq(poppedMessage_2.recipient, message_4.recipient);
assertEq(poppedMessage_2.message, message_4.message);
assertEq(poppedMessage_2.value, message_4.value);
}

function testPopNextMessageNotByAgent() public {
DoubleEndedStructQueue.MessageContainer memory message = buildMessage();
function testPopMessageNotByAgent() public {
DoubleEndedStructQueue.MessageContainer memory message = buildMessage("Hello!");
vm.deal(agent, 1 ether);
vm.startPrank(agent);
agentComm.sendMessage{value: 10000000000000}(agent, message.message);
Expand All @@ -144,15 +171,15 @@ contract AgentCommunicationTest is Test {
address notAgent = address(0x789);
vm.startPrank(notAgent);
vm.expectRevert(AgentCommunication.MessageNotSentByAgent.selector);
agentComm.popNextMessage(agent);
agentComm.popMessageAtIndex(agent, 0);
vm.stopPrank();
}

function testCountMessages() public {
// Initialize a message
DoubleEndedStructQueue.MessageContainer memory message1 = buildMessage();
DoubleEndedStructQueue.MessageContainer memory message1 = buildMessage("Hello!");

DoubleEndedStructQueue.MessageContainer memory message2 = buildMessage();
DoubleEndedStructQueue.MessageContainer memory message2 = buildMessage("Hello!");

// Fund the agent and start the prank
vm.deal(agent, 1 ether);
Expand Down
Loading