1use super::{
5 account_address::AccountAddress,
6 identifier::Identifier,
7 language_storage::{ModuleId, StructTag, TypeTag},
8};
9use anyhow::{format_err, Error, Result};
10use std::collections::btree_map::{self, BTreeMap};
11
12#[derive(Debug, Clone)]
14pub struct AccountChangeSet {
15 pub modules: BTreeMap<Identifier, Option<Vec<u8>>>,
16 pub resources: BTreeMap<StructTag, Option<Vec<u8>>>,
17}
18
19fn publish_checked<K, V, F>(map: &mut BTreeMap<K, Option<V>>, k: K, v: V, make_err: F) -> Result<()>
20where
21 K: Ord,
22 F: FnOnce() -> Error,
23{
24 match map.entry(k) {
25 btree_map::Entry::Occupied(entry) => {
26 let r = entry.into_mut();
27 match r {
28 Some(_) => return Err(make_err()),
29 None => *r = Some(v),
30 }
31 }
32 btree_map::Entry::Vacant(entry) => {
33 entry.insert(Some(v));
34 }
35 }
36 Ok(())
37}
38
39fn unpublish_checked<K, V, F>(map: &mut BTreeMap<K, Option<V>>, k: K, make_err: F) -> Result<()>
40where
41 K: Ord,
42 F: FnOnce() -> Error,
43{
44 match map.entry(k) {
45 btree_map::Entry::Occupied(entry) => {
46 let r = entry.into_mut();
47 match r {
48 Some(_) => *r = None,
49 None => return Err(make_err()),
50 }
51 }
52 btree_map::Entry::Vacant(entry) => {
53 entry.insert(None);
54 }
55 }
56 Ok(())
57}
58
59impl AccountChangeSet {
60 pub fn new() -> Self {
61 Self {
62 modules: BTreeMap::new(),
63 resources: BTreeMap::new(),
64 }
65 }
66
67 pub fn squash(&mut self, other: Self) -> Result<()> {
68 for (name, blob_opt) in other.modules {
69 match blob_opt {
70 Some(blob) => self.publish_module(name, blob)?,
71 None => self.unpublish_module(name)?,
72 }
73 }
74 for (struct_tag, blob_opt) in other.resources {
75 match blob_opt {
76 Some(blob) => self.publish_resource(struct_tag, blob)?,
77 None => self.unpublish_resource(struct_tag)?,
78 }
79 }
80 Ok(())
81 }
82
83 pub fn publish_or_overwrite_module(&mut self, name: Identifier, blob: Vec<u8>) {
84 self.modules.insert(name, Some(blob));
85 }
86
87 pub fn publish_or_overwrite_resource(&mut self, struct_tag: StructTag, blob: Vec<u8>) {
88 self.resources.insert(struct_tag, Some(blob));
89 }
90
91 pub fn publish_module(&mut self, name: Identifier, blob: Vec<u8>) -> Result<()> {
92 publish_checked(&mut self.modules, name, blob, || {
93 format_err!("module already published")
94 })
95 }
96
97 pub fn unpublish_module(&mut self, name: Identifier) -> Result<()> {
98 unpublish_checked(&mut self.modules, name, || {
99 format_err!("module already unpublished")
100 })
101 }
102
103 pub fn publish_resource(&mut self, struct_tag: StructTag, blob: Vec<u8>) -> Result<()> {
104 publish_checked(&mut self.resources, struct_tag, blob, || {
105 format_err!("resource already published")
106 })
107 }
108
109 pub fn unpublish_resource(&mut self, struct_tag: StructTag) -> Result<()> {
110 unpublish_checked(&mut self.resources, struct_tag, || {
111 format_err!("resource already unpublished")
112 })
113 }
114}
115
116#[derive(Debug, Clone)]
118pub struct ChangeSet {
119 pub accounts: BTreeMap<AccountAddress, AccountChangeSet>,
120}
121
122impl ChangeSet {
123 pub fn new() -> Self {
124 Self {
125 accounts: BTreeMap::new(),
126 }
127 }
128
129 fn get_or_insert_account_changeset(&mut self, addr: AccountAddress) -> &mut AccountChangeSet {
130 match self.accounts.entry(addr) {
131 btree_map::Entry::Occupied(entry) => entry.into_mut(),
132 btree_map::Entry::Vacant(entry) => entry.insert(AccountChangeSet::new()),
133 }
134 }
135
136 pub fn publish_or_overwrite_module(&mut self, module_id: ModuleId, blob: Vec<u8>) {
137 let (addr, name) = module_id.into();
138 let account_changeset = self.get_or_insert_account_changeset(addr);
139 account_changeset.publish_or_overwrite_module(name, blob)
140 }
141
142 pub fn publish_module(&mut self, module_id: ModuleId, blob: Vec<u8>) -> Result<()> {
143 let (addr, name) = module_id.into();
144 let account_changeset = self.get_or_insert_account_changeset(addr);
145 account_changeset.publish_module(name, blob)
146 }
147
148 pub fn unpublish_module(&mut self, module_id: ModuleId) -> Result<()> {
149 let (addr, name) = module_id.into();
150 let account_changeset = self.get_or_insert_account_changeset(addr);
151 account_changeset.unpublish_module(name)
152 }
153
154 pub fn publish_or_overwrite_resource(
155 &mut self,
156 addr: AccountAddress,
157 struct_tag: StructTag,
158 blob: Vec<u8>,
159 ) {
160 self.get_or_insert_account_changeset(addr)
161 .publish_or_overwrite_resource(struct_tag, blob)
162 }
163
164 pub fn publish_resource(
165 &mut self,
166 addr: AccountAddress,
167 struct_tag: StructTag,
168 blob: Vec<u8>,
169 ) -> Result<()> {
170 self.get_or_insert_account_changeset(addr)
171 .publish_resource(struct_tag, blob)
172 }
173
174 pub fn unpublish_resource(
175 &mut self,
176 addr: AccountAddress,
177 struct_tag: StructTag,
178 ) -> Result<()> {
179 self.get_or_insert_account_changeset(addr)
180 .unpublish_resource(struct_tag)
181 }
182
183 pub fn squash(&mut self, other: Self) -> Result<()> {
184 for (addr, other_account_changeset) in other.accounts {
185 match self.accounts.entry(addr) {
186 btree_map::Entry::Occupied(mut entry) => {
187 entry.get_mut().squash(other_account_changeset)?;
188 }
189 btree_map::Entry::Vacant(entry) => {
190 entry.insert(other_account_changeset);
191 }
192 }
193 }
194 Ok(())
195 }
196
197 pub fn into_modules(self) -> impl Iterator<Item = (ModuleId, Option<Vec<u8>>)> {
198 self.accounts.into_iter().flat_map(|(addr, account)| {
199 account
200 .modules
201 .into_iter()
202 .map(move |(module_name, blob_opt)| (ModuleId::new(addr, module_name), blob_opt))
203 })
204 }
205
206 pub fn modules(&self) -> impl Iterator<Item = (AccountAddress, &Identifier, Option<&[u8]>)> {
207 self.accounts.iter().flat_map(|(addr, account)| {
208 let addr = *addr;
209 account.modules.iter().map(move |(module_name, blob_opt)| {
210 (addr, module_name, blob_opt.as_ref().map(|v| v.as_ref()))
211 })
212 })
213 }
214
215 pub fn resources(&self) -> impl Iterator<Item = (AccountAddress, &StructTag, Option<&[u8]>)> {
216 self.accounts.iter().flat_map(|(addr, account)| {
217 let addr = *addr;
218 account.resources.iter().map(move |(struct_tag, blob_opt)| {
219 (addr, struct_tag, blob_opt.as_ref().map(|v| v.as_ref()))
220 })
221 })
222 }
223}
224
225pub type Event = (Vec<u8>, u64, TypeTag, Vec<u8>);