[Twisted-Python] pb.Copyable, round trip objects, and untrusted clients
dripton at ripton.net
Thu May 20 23:46:53 EDT 2004
On 2004.05.20 13:07:06 +0000, Christopher Armstrong wrote:
> Well, your example didn't look like it had much use for using
> particularly complex state going both ways. Maybe you can explain this
> game-choosing process in a bit more detail? Without knowing any more,
> letting the user choose which game he wants to play sounds like it
> shouldn't be more complex than the server giving the client a list of
> strings of game-names (like "Bob's l33t Server") and the client sending
> back "Bob's l33t Server" in a request later on.
The full game has much more complex state, which I will resist spelling
out in detail. I was just trying to show a minimal example.
Yes, that particular event would only really require sending a list of
dicts or tuples, with each dict or tuple holding the ~6 attributes of
a single game that need to be displayed in a table, from server to
client. And then sending just the name or id of the one game that
the user wants to join back to the server. (Another event would send a
different subset of the game state.)
But there is a (small) code size cost to pass just the attributes of
the Game class that are needed for that GUI display. Passing the
whole Game class (censored in a global rather than event-specific way)
is simpler. And if I decide to add another column to that table,
passing the whole object probably doesn't require a change to the
remote call arguments, while passing the minimal bits does. And it just
feels like better OO design to pass a whole object rather than ripping
out bits and pieces of it.
None of which matters much, if passing just dicts and strings and ints
is secure, and passing copies of complex objects is not. (This seems to
happen in every "distributed object system" I try. Basic RPC works
[except in Java RMI, which appears to be an April Fool's joke];
anything more complex works for "Hello World" then falls over in
Passing globally reusable game state from server to clients in a
consistent, systematic way makes a lot more sense than providing
minimal ad hoc local context for each distinct action.
There are two opposite ways to do this, which in the end generate
mostly the same result.
A. Apply the (error-checked) action on the server, then use Copyable or
Cacheable to copy the new state (except the hidden parts) over to the
clients. The clients hold a slightly delayed mirror image of the
B. Initialize separate objects of the same classes on the server and
each client to the same starting state, then pass the same action that
just ran on the server to each client (except hidden events). If you
assume that all actions are deterministic (meaning die rolls are
separate actions), the same code running the same actions will
generate the same end state. The server and client are now more
like blind synchronized swimmers listening to the same coach.
B is more work up front. However, assuming applying an action to a
state to get the next state is cheap (and cheaply reversable), I think
it's superior. First, it uses more CPU on clients and less network
bandwidth, which is a good tradeoff. Second, you have the full event
stream so you can easily undo/redo, either for real or to just step
through previous game history. Finally, client -> server traffic has
to be small (attempted) actions, not full object dumps, because the
server doesn't trust the client, so it has the beauty of symmetry.
> IOW, the poster who said that your second and third points are basically
> the same is correct; the API you're designing needs to be looked at
> specifically to see the optimal secure/easy solution.
Upon further review, I'm back to throwing minimal action objects both
ways, eschewing Copyable and Cacheable completely in favor of manual
solutions involving dicts and lists of strings and ints. Which is
where I was a couple of weeks ago. The grass is always greener...
The security issues in Copyable / Cacheable should knock me off this
particular fence for long enough to have enough code written that I'm
unwilling to climb back up.
David Ripton dripton at ripton.net
More information about the Twisted-Python