# Mapping, structs and ledger accounting

## 01 — Bài toán
Thiết kế một Smart Contract có thể được nhiều địa chỉ gọi mà không cần tin cậy một backend quản lý state.

## 02 — Vấn đề
Code chạy trong EVM, mỗi state write tiêu tốn gas và giao dịch có thể bị gọi từ bất kỳ địa chỉ nào. Java `private` không tương đương với bí mật on-chain.

## 03 — Giải pháp
Áp dụng các primitive Solidity đúng ngữ cảnh, xác minh preconditions, cập nhật state nhất quán và kiểm thử trường hợp thất bại.

## 04 — Lý thuyết
Mappings default to zero values and are not enumerable; `struct` groups account fields. A Solidity mapping is unlike an iterable Java `Map`.

**So sánh Java:** contract giống một stateful service được nhân bản theo đồng thuận; `msg.sender` tương tự authenticated caller nhưng không tự đảm bảo user identity; storage tồn tại trên chain, không giống Java heap.

**Dependency:** M04 EVM; M05 bài trước nếu có.

# 05 — Hands-on lab: Mapping, structs and ledger accounting

## Chuẩn bị
- Foundry (forge, cast, anvil); Solidity 0.8.24
- Chạy hoàn toàn local, không dùng mainnet funds

## Thực hiện
1. Đọc `theory.md` và `solution/src/Lab.sol`, xác định state, invariants và external calls.
2. Tự triển khai `starter/src/Lab.sol` trước khi xem solution.
3. Viết các test trong `starter/test/Lab.t.sol`.
4. `cd solution && forge build && forge test -vvv`
5. `forge test --gas-report` để quan sát chi phí.
6. `forge test -vvvv` nếu test fail, đọc call trace và revert reason.

## Các test trong reference
- `testCredit`
- `testIsolation`
- `testZeroReverts`

## Expected output
`forge build` thành công, tất cả các test trên PASS. Đây là kết quả **dự kiến**, chưa được xác minh trong môi trường đóng gói vì không có forge/solc.

## Troubleshooting
- `forge: command not found`: cài Foundry chính thức.
- Compiler download error: kiểm tra network và solc_version.
- Assertion failure: chạy `forge test -vvvv` để xem trace.

# 07 — Exercises

1. Implement contract và test từ đầu trong `starter/`, không copy solution.
2. Implement `debit` and enforce totalCredit equals the sum of known accounts in tests.
3. Bổ sung ít nhất một negative test (revert) và một edge case.
4. Viết giải thích vì sao state thay đổi hoặc revert; so sánh với Java service.

**Acceptance criteria:** `forge build` pass; toàn bộ test pass; không sử dụng tài sản mainnet; README ghi các invariants và assumptions.

# 08 — Interview

**Q1: Vì sao contract cần kiểm tra `msg.sender`?** Bởi mọi địa chỉ đều có thể gửi transaction; quyền phải được enforce on-chain, không thể chỉ dựa vào API gateway.

**Q2: `view` và `pure` khác nhau thế nào?** `view` có thể đọc state nhưng không sửa state; `pure` không đọc hoặc sửa state contract.

**Q3: Revert ảnh hưởng gì?** State updates trong phạm vi bị revert được rollback, nhưng gas đã tiêu thụ không được hoàn lại hoàn toàn.

**Q4: Mapping, structs and ledger accounting có rủi ro gì?** Kiểm tra access control, arithmetic bounds, external calls, assumptions về người gọi và accounting invariants.
